Add build script.

This commit is contained in:
luxick
2018-02-19 22:56:31 +01:00
parent f90930c617
commit 2e8411c6b4
181 changed files with 288 additions and 284 deletions

View File

@@ -1,2 +0,0 @@
from cardvault import application
application.main()

17
build.py Normal file
View File

@@ -0,0 +1,17 @@
"""
Package cardvault using zipapp into an executable zip archive
"""
import os
import zipapp
INTERPRETER = '/usr/bin/env python3'
TARGET_FILENAME = 'cardvault'
# The bundled file should be placed into the build directory
target_path = os.path.join(os.path.dirname(__file__), 'build')
# Make sure it exists
if not os.path.isdir(target_path):
os.mkdir(target_path)
target = os.path.join(target_path, TARGET_FILENAME)
# Create archive
zipapp.create_archive(source='cardvault', target=target, interpreter=INTERPRETER)

View File

@@ -1 +0,0 @@
from cardvault import application

10
cardvault/__main__.py Normal file
View File

@@ -0,0 +1,10 @@
import sys
import os.path
path = os.path.realpath(os.path.abspath(__file__))
sys.path.insert(0, os.path.dirname(path))
from cv_gtk3 import gtk_ui
if __name__ == '__main__':
gtk_ui.main()

View File

@@ -1,4 +1,3 @@
import json
import os import os
import itertools import itertools
@@ -8,8 +7,7 @@ from cv_engine.util import EngineConfig, EngineConstants, Utilities
class CardvaultEngine: class CardvaultEngine:
def __init__(self, config_file=False): def __init__(self, config_file=False):
""" """ Create a new cv_engine instance
Create a new cv_engine instance
:param config_file: File path of the configuration file :param config_file: File path of the configuration file
""" """
if config_file: if config_file:
@@ -18,23 +16,20 @@ class CardvaultEngine:
self.database = CardvaultDB(db_file_path) self.database = CardvaultDB(db_file_path)
def get_card(self, card_id): def get_card(self, card_id):
""" """ Load a card object from database
Load a card object from database
:param card_id: multiverse id of a card :param card_id: multiverse id of a card
:return: an cv_engine.model.Card object :return: an cv_engine.model.Card object
""" """
return self.database.card_load(card_id) return self.database.card_load(card_id)
def get_library(self) -> list: def get_library(self) -> list:
""" """ Get the complete library of cards
Get the complete library of cards
:return: Alphabetically ordered list of all cards in library :return: Alphabetically ordered list of all cards in library
""" """
return self.database.lib_get_all() return self.database.lib_get_all()
def get_all_categories(self) -> dict: def get_all_categories(self) -> dict:
""" """ Get all categories an the cards that are contained within them
Get all categories an the cards that are contained within them
:return: A dict with the category names and cv_engine.models.Card objects as values :return: A dict with the category names and cv_engine.models.Card objects as values
""" """
categories = self.database.category_get_all() categories = self.database.category_get_all()
@@ -54,25 +49,5 @@ class CardvaultEngine:
if __name__ == "__main__": if __name__ == "__main__":
# Test code
engine = CardvaultEngine() engine = CardvaultEngine()
# Insert Data into Datasbase
# print("Database insert test:")
# engine.database.db_clear_data_card()
# cards = Utilities.parse_mtgjson_cards(json.load(open("/home/luxick/Downloads/AllSets-x.json")))
# engine.database.card_insert_many(cards)
# Compare JSON Data to Data in Database
# for card in Utilities.parse_mtgjson_cards(json.load(open("/home/luxick/Downloads/AllSets-x.json"))):
# if card.multiverse_id:
# print('From JSON: {}'.format(card.names))
# print('From DB: {}\n'.format(engine.database.card_load(card.multiverse_id).names))
# Search test
# term = 'fire'
# for result in engine.database.card_search_by_name(term):
# print(str(result), end='\n\n')
# Fast load test
# engine.database.card_fast_load()
# all_ids = engine.database.db_all_multiverse_ids()
# print('Loaded IDs: {}'.format(len(all_ids)))

View File

@@ -35,14 +35,6 @@ class EngineConstants:
config_path = os.path.join(os.path.expanduser('~'), '.config', 'cardvault') config_path = os.path.join(os.path.expanduser('~'), '.config', 'cardvault')
class GTKConstants:
"""
Constants for the GTK Ui
"""
# Directory in witch glade ui files are stored
glade_files = '/gui'
class MTGConstants: class MTGConstants:
""" """
This class contains constants that can be used within the whole program This class contains constants that can be used within the whole program
@@ -98,13 +90,3 @@ class Utilities:
cards.append(c) cards.append(c)
output = output + cards output = output + cards
return output return output
@staticmethod
def expand_file_path(base_file, sub_dirs) -> str:
"""
Get absolute file path relative to another file
:param base_file: Current file from witch to expand
:param sub_dirs: List of sub directories to desired file
:return: Full file path of chosen file
"""
return os.path.join(os.path.dirname(base_file), *sub_dirs)

View File

@@ -8,9 +8,8 @@ from cv_engine.util import MTGConstants
class CardView(Gtk.ScrolledWindow): class CardView(Gtk.ScrolledWindow):
""" Class for displaying a list of cards in an GTKTreeView """ """ Class for displaying a list of cards in an GTKTreeView """
def __init__(self, ui_file, filtered): def __init__(self, filtered):
""" Constructor for a card list display """ Constructor for a card list display
:param ui_file: Full path to an CardView glade file
:param filtered: Should the card list be filterable :param filtered: Should the card list be filterable
""" """
self.filtered = filtered self.filtered = filtered
@@ -21,12 +20,13 @@ class CardView(Gtk.ScrolledWindow):
self.set_vexpand(True) self.set_vexpand(True)
# Build UI # Build UI
self.ui = Gtk.Builder() self.ui = Gtk.Builder()
self.ui.add_from_file(ui_file) self.ui.add_from_string(GTKUtilities.load_ui_resource('cardtree.glade'))
self.tree = self.ui.get_object('cardTree') self.tree = self.ui.get_object('cardTree')
self.store = self.ui.get_object('cardStore') self.store = self.ui.get_object('cardStore')
self.store.set_sort_func(4, self.compare_rarity, None) self.store.set_sort_func(4, self.compare_rarity, None)
# Add the TreeView # Add the TreeView
self.add(self.tree) self.add(self.tree)
#self.tree.connect("row-activated", self.on_row_double_click)
def get_selected_cards(self): def get_selected_cards(self):
""" Get the currently selected cards in the TreeView """ Get the currently selected cards in the TreeView

View File

@@ -1,6 +1,7 @@
import gi
import os import os
import gi
gi.require_version('Gtk', '3.0') gi.require_version('Gtk', '3.0')
from gi.repository import Gtk from gi.repository import Gtk
@@ -17,13 +18,11 @@ class CardvaultGTK(MainWindowFunctions):
def __init__(self): def __init__(self):
# Start engine (without config file) # Start engine (without config file)
self.engine = engine.CardvaultEngine() self.engine = engine.CardvaultEngine()
# Set Glade file location
GUISettings.glade_file_path = os.path.join(os.path.dirname(__file__), 'gui')
# Load Glade files # Load Glade files
glade_files = ['mainwindow.glade', 'search.glade', 'overlays.glade'] glade_files = ['mainwindow.glade', 'search.glade', 'overlays.glade']
self.ui = Gtk.Builder() self.ui = Gtk.Builder()
for file in glade_files: for file in glade_files:
self.ui.add_from_file(os.path.join(GUISettings.glade_file_path, file)) self.ui.add_from_string(GTKUtilities.load_ui_resource(file))
# Set pages for the ui to use # Set pages for the ui to use
GUISettings.pages = { GUISettings.pages = {
"search": self.ui.get_object("searchView"), "search": self.ui.get_object("searchView"),
@@ -34,8 +33,7 @@ class CardvaultGTK(MainWindowFunctions):
if not os.path.isdir(util.EngineConfig.icon_cache_path): if not os.path.isdir(util.EngineConfig.icon_cache_path):
os.mkdir(util.EngineConfig.icon_cache_path) os.mkdir(util.EngineConfig.icon_cache_path)
# Load single mana icons # Load single mana icons
GTKUtilities.mana_icons = GTKUtilities.load_icon_cache(os.path.join(os.path.dirname(__file__), 'resources', GTKUtilities.mana_icons = GTKUtilities.load_icon_cache(os.path.join(GTKUtilities.resources_path, 'mana'))
'mana'))
# Load the the pre constructed icon cache # Load the the pre constructed icon cache
GTKUtilities.precon_icon_cache = GTKUtilities.load_icon_cache(util.EngineConfig.icon_cache_path) GTKUtilities.precon_icon_cache = GTKUtilities.load_icon_cache(util.EngineConfig.icon_cache_path)
# Call constructor of superclasses # Call constructor of superclasses
@@ -48,7 +46,12 @@ class CardvaultGTK(MainWindowFunctions):
self.hide_initial_widgets() self.hide_initial_widgets()
self.switch_page('search') self.switch_page('search')
if __name__ == '__main__':
def main():
CardvaultGTK() CardvaultGTK()
Gtk.main() Gtk.main()
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,176 @@
import os
import re
from gi.repository import GdkPixbuf
from zipfile import ZipFile
try:
from PIL import Image
except ImportError as err:
print('PIL imaging library is not installed')
from cv_engine.util import EngineConfig
class GTKUtilities:
""" Access to image caches and utilities for use in the GTK application """
# Loaded mana symbols Format: {'B': GDKPixbuf, '3': GDKPixbuf}
mana_icons = {}
# Cache for combined mana cost icons
precon_icon_cache = {}
# Path of Gtk resources relative to cardvault base package
resources_path = os.path.join('cv_gtk3', 'resources')
@staticmethod
def get_path_from_base_dir(*dirs):
return os.path.join(os.path.dirname(os.path.dirname(__file__)), *dirs)
@staticmethod
def get_mana_icons(mana_string):
""" Return the combined mana symbols for a mana string
:param mana_string: String in the format '{3}{U}{B}'
:return: GdkPixbuf containing the combined symbols
"""
if not mana_string:
return
icon_list = re.findall("{(.*?)}", mana_string.replace("/", "-"))
icon_name = "_".join(icon_list)
try:
icon = GTKUtilities.precon_icon_cache[icon_name]
except KeyError:
icon = GTKUtilities.create_mana_icons(mana_string)
GTKUtilities.precon_icon_cache[icon_name] = icon
# Scale icon for display
if icon:
icon = icon.scale_simple(icon.get_width() / 5, icon.get_height() / 5, GdkPixbuf.InterpType.HYPER)
return icon
@staticmethod
def create_mana_icons(mana_string):
# Convert the string to a List
glyphs = re.findall("{(.*?)}", mana_string)
if len(glyphs) == 0:
return
# Compute horizontal size for the final image
size = len(glyphs) * 105
image = Image.new("RGBA", (size, 105))
for index, icon in enumerate(glyphs):
x_pos = index * 105
try:
# Try loading mana icon and converting to PIL.Image for combining
loaded = GTKUtilities.pixbuf_to_image(GTKUtilities.mana_icons[icon])
except KeyError:
print('Mana icon "{}" is not loaded.'.format(icon))
return
image.paste(loaded, (x_pos, 0))
# Save pre build icon file
path = os.path.join(EngineConfig.icon_cache_path, "_".join(glyphs) + ".png")
image.save(path)
try:
pixbuf = GdkPixbuf.Pixbuf.new_from_file(path)
except Exception as ex:
print(ex)
return
return pixbuf
@staticmethod
def pixbuf_to_image(pix):
"""Convert gdkpixbuf to PIL image"""
data = pix.get_pixels()
w = pix.props.width
h = pix.props.height
stride = pix.props.rowstride
mode = "RGB"
if pix.props.has_alpha:
mode = "RGBA"
im = Image.frombytes(mode, (w, h), data, "raw", mode, stride)
return im
@staticmethod
def load_ui_resource(resource_name):
""" Load GUI resource depending on the execution mode (from a directory or from a zip file)
:param resource_name: Name of the glade file
:return: String content of the resource file
"""
if os.path.isdir(os.path.dirname(__file__)):
return GTKUtilities.load_ui_resource_file(os.path.join(GTKUtilities.resources_path, 'gui', resource_name))
else:
zip_path = os.path.dirname(os.path.dirname(__file__))
return GTKUtilities.load_ui_resource_zip(zip_path,
os.path.join(GTKUtilities.resources_path, 'gui', resource_name))
@staticmethod
def load_ui_resource_file(resource_path):
""" LOad GUI resource from file path
:param resource_path: Relative path of the resource based on the cardvault base package
:return: String content of the resource file
"""
full_path = GTKUtilities.get_path_from_base_dir(resource_path)
with open(full_path, 'r') as file:
return file.read()
@staticmethod
def load_ui_resource_zip(archive_file, resource_path):
""" Load GUI resource from a zip archive (for usage in release mode)
:param archive_file: Full path of the archive file
:param resource_path: Path of the resources within the archive
:return: String representation of the file content
"""
with ZipFile(archive_file, 'r') as archive:
return archive.read(resource_path).decode('utf-8')
@staticmethod
def load_icon_cache(icon_path):
""" Get a dictionary with all available mana icons
:param icon_path: Relative path of icon resource files
:return: Dict with icon names and Gdkpixbuf objects
"""
if os.path.isdir(GTKUtilities.get_path_from_base_dir(icon_path)):
return GTKUtilities.load_icon_cache_file(GTKUtilities.get_path_from_base_dir(icon_path))
else:
zip_path = os.path.dirname(os.path.dirname(__file__))
return GTKUtilities.load_icon_cache_zip(zip_path)
@staticmethod
def load_icon_cache_file(icon_path):
""" Load icon cache from absolute paths at file system
:param icon_path: Relative path of icon resource files
:return: Dict with icon names and Gdkpixbuf object
"""
icons = {}
files = os.listdir(icon_path)
for file in files:
try:
pixbuf = GdkPixbuf.Pixbuf.new_from_file(os.path.join(icon_path, file))
# Strip filename extension
icon_name = os.path.splitext(file)[0]
icons[icon_name] = pixbuf
except Exception as ex:
print('Error while loading icon file "{}"'.format(ex))
return icons
@staticmethod
def load_icon_cache_zip(zip_path):
""" Load icon cache from zipped archive
:param zip_path: Full path of the zip archive
:return: Dict with icon names and Gdkpixbuf object
"""
with ZipFile(zip_path, 'r') as archive:
icon_path = os.path.join('cv_gtk3', 'resources', 'mana')
files = [path for path in archive.namelist() if os.path.isfile(path.startswith(icon_path))]
icons = {}
for file in files:
with archive.open(file) as data:
try:
loader = GdkPixbuf.PixbufLoader()
loader.write(data.read())
pixbuf = loader.get_pixbuf()
loader.close()
# Strip filename extension
icon_name = os.path.splitext(file)[0]
icons[icon_name] = pixbuf
except Exception as ex:
print('Error while loading icon file "{0}"\n{1}'.format(file, ex))
return icons

View File

@@ -6,7 +6,7 @@
<property name="name">Card Vault</property> <property name="name">Card Vault</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="title" translatable="yes">Card Vault</property> <property name="title" translatable="yes">Card Vault</property>
<property name="default_width">900</property> <property name="default_width">1200</property>
<property name="default_height">700</property> <property name="default_height">700</property>
<property name="icon_name">cardvault</property> <property name="icon_name">cardvault</property>
<signal name="delete-event" handler="do_delete_event" swapped="no"/> <signal name="delete-event" handler="do_delete_event" swapped="no"/>

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 147 KiB

After

Width:  |  Height:  |  Size: 147 KiB

View File

Before

Width:  |  Height:  |  Size: 225 KiB

After

Width:  |  Height:  |  Size: 225 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -1,14 +1,12 @@
import os import os
from cv_gtk3.card_view import CardView from cv_gtk3.card_view import CardView
from cv_gtk3.setting import GUISettings from cv_gtk3.gtk_util import GTKUtilities
from cv_gtk3.gtkui import CardvaultGTK
class SearchPageHandlers: class SearchPageHandlers:
""" Class for handling Signals from the search page """ """ Class for handling Signals from the search page """
def __init__(self, app: 'CardvaultGTK'): def __init__(self, app):
""" Constructor """ Constructor
:param app: Reference to an CardvaultGTK object :param app: Reference to an CardvaultGTK object
""" """
@@ -16,7 +14,7 @@ class SearchPageHandlers:
# Build the card view # Build the card view
overlay = self.app.ui.get_object("searchResults") overlay = self.app.ui.get_object("searchResults")
self.card_list = CardView(ui_file=os.path.join(GUISettings.glade_file_path, 'cardtree.glade'), filtered=False) self.card_list = CardView(filtered=False)
self.card_list.set_name("resultsScroller") self.card_list.set_name("resultsScroller")
# TODO Context menu for card view # TODO Context menu for card view
# card_list.tree.connect("row-activated", self.on_search_card_selected) # card_list.tree.connect("row-activated", self.on_search_card_selected)

View File

@@ -1,8 +0,0 @@
[Desktop Entry]
Version=0.5
Type=Application
Name=Card Vault
Comment=Organize and plan your MTG card collection
TryExec=cardvault
Exec=cardvault
Icon=cardvault

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -1,95 +0,0 @@
import re
import os
from gi.repository import GdkPixbuf
try:
from PIL import Image as PImage
except ImportError as err:
print('PIL imaging library is not installed')
from cv_engine.util import EngineConfig
class GTKUtilities:
""" Access to image caches and utilities for use in the GTK application """
# Loaded mana symbols Format: {'B': GDKPixbuf, '3': GDKPixbuf}
mana_icons = {}
# Cache for combined mana cost icons
precon_icon_cache = {}
@staticmethod
def load_icon_cache(path):
icons = {}
if not os.path.isdir(path):
os.mkdir(path)
files = os.listdir(path)
for file in files:
try:
pixbuf = GdkPixbuf.Pixbuf.new_from_file(os.path.join(path, file))
# Strip filename extension
icon_name = os.path.splitext(file)[0]
icons[icon_name] = pixbuf
except Exception as ex:
print('Error while loading icon file "{}"'.format(ex))
return icons
@staticmethod
def get_mana_icons(mana_string):
""" Return the combined mana symbols for a mana string
:param mana_string: String in the format '{3}{U}{B}'
:return: GdkPixbuf containing the combined symbols
"""
if not mana_string:
return
icon_list = re.findall("{(.*?)}", mana_string.replace("/", "-"))
icon_name = "_".join(icon_list)
try:
icon = GTKUtilities.precon_icon_cache[icon_name]
except KeyError:
icon = GTKUtilities.create_mana_icons(mana_string)
GTKUtilities.precon_icon_cache[icon_name] = icon
# Scale icon for display
if icon:
icon = icon.scale_simple(icon.get_width() / 5, icon.get_height() / 5, GdkPixbuf.InterpType.HYPER)
return icon
@staticmethod
def create_mana_icons(mana_string):
# Convert the string to a List
glyphs = re.findall("{(.*?)}", mana_string)
if len(glyphs) == 0:
return
# Compute horizontal size for the final image
size = len(glyphs) * 105
image = PImage.new("RGBA", (size, 105))
for index, icon in enumerate(glyphs):
x_pos = index * 105
try:
# Try loading mana icon and converting to PIL.Image for combining
loaded = GTKUtilities.pixbuf_to_image(GTKUtilities.mana_icons[icon])
except KeyError:
print('Mana icon "{}" is not loaded.'.format(icon))
return
image.paste(loaded, (x_pos, 0))
# Save pre build icon file
path = os.path.join(EngineConfig.icon_cache_path, "_".join(glyphs) + ".png")
image.save(path)
try:
pixbuf = GdkPixbuf.Pixbuf.new_from_file(path)
except Exception as err:
print(err)
return
return pixbuf
@staticmethod
def pixbuf_to_image(pix):
"""Convert gdkpixbuf to PIL image"""
data = pix.get_pixels()
w = pix.props.width
h = pix.props.height
stride = pix.props.rowstride
mode = "RGB"
if pix.props.has_alpha:
mode = "RGBA"
im = PImage.frombytes(mode, (w, h), data, "raw", mode, stride)
return im

View File

@@ -1,5 +1,3 @@
from collections import OrderedDict
import gi import gi
import os import os
import copy import copy
@@ -56,8 +54,8 @@ class Application:
self.wants = Dict[str, List[Type[mtgsdk.Card]]] self.wants = Dict[str, List[Type[mtgsdk.Card]]]
self.load_user_data() self.load_user_data()
self.ui.get_object('statusbar_icon').set_from_icon_name( self.ui.get_object('statusbar_icon').set_from_icon_name(util.online_icons[self.is_online()],
util.online_icons[self.is_online()], Gtk.IconSize.BUTTON) Gtk.IconSize.BUTTON)
self.ui.get_object('statusbar_icon').set_tooltip_text(util.online_tooltips[self.is_online()]) self.ui.get_object('statusbar_icon').set_tooltip_text(util.online_tooltips[self.is_online()])
self.handlers = handlers.Handlers(self) self.handlers = handlers.Handlers(self)
@@ -95,35 +93,34 @@ class Application:
builder.add_from_file(util.get_ui_filename("detailswindow.glade")) builder.add_from_file(util.get_ui_filename("detailswindow.glade"))
builder.add_from_file(util.get_ui_filename("overlays.glade")) builder.add_from_file(util.get_ui_filename("overlays.glade"))
window = builder.get_object("cardDetails") window = builder.get_object("cardDetails")
window.set_title(card.name) window.set_title(card.get('name'))
# Card Image # Card Image
container = builder.get_object("imageContainer") container = builder.get_object("imageContainer")
pixbuf = util.load_card_image(card, 63 * 5, 88 * 5, self.image_cache) pixbuf = util.load_card_image(card, 63 * 5, 88 * 5, self.image_cache)
image = Gtk.Image().new_from_pixbuf(pixbuf) image = Gtk.Image().new_from_pixbuf(pixbuf)
container.add(image) container.add(image)
# Name # Name
builder.get_object("cardName").set_text(card.name) builder.get_object("cardName").set_text(card.get('name'))
# Types # Types
supertypes = "" supertypes = ""
if card.subtypes is not None: if card.get('subtypes'):
supertypes = " - " + " ".join(card.subtypes) supertypes = " - " + " ".join(card.get('subtypes'))
types = " ".join(card.types) + supertypes types = " ".join(card.get('types')) + supertypes
builder.get_object("cardTypes").set_text(types) builder.get_object("cardTypes").set_text(types)
# Rarity # Rarity
builder.get_object("cardRarity").set_text(card.rarity if card.rarity else "") builder.get_object("cardRarity").set_text(card.get('rarity') or "")
# Release # Release
builder.get_object("cardReleaseDate").set_text(card.release_date if card.release_date else "") builder.get_object("cardReleaseDate").set_text(card.get('release_date') or "")
# Set # Set
builder.get_object("cardSet").set_text(card.set_name) builder.get_object("cardSet").set_text(card.get('set_name'))
# Printings # Printings
prints = [] all_sets = self.get_all_sets()
for set in card.printings: prints = [all_sets[set_name].get('name') for set_name in card.get('printings')]
prints.append(self.get_all_sets()[set].name)
builder.get_object("cardPrintings").set_text(", ".join(prints)) builder.get_object("cardPrintings").set_text(", ".join(prints))
# Legalities # Legalities
grid = builder.get_object("legalitiesGrid") grid = builder.get_object("legalitiesGrid")
rows = 1 rows = 1
for legality in card.legalities if card.legalities else {}: for legality in card.get('legalities') or {}:
date_label = Gtk.Label() date_label = Gtk.Label()
date_label.set_halign(Gtk.Align.END) date_label.set_halign(Gtk.Align.END)
text_label = Gtk.Label() text_label = Gtk.Label()
@@ -140,9 +137,9 @@ class Application:
grid.show_all() grid.show_all()
# Rulings # Rulings
if card.rulings: if card.get('rulings'):
store = builder.get_object("rulesStore") store = builder.get_object("rulesStore")
for rule in card.rulings: for rule in card.get('rulings'):
store.append([rule["date"], rule["text"]]) store.append([rule["date"], rule["text"]])
else: else:
builder.get_object("ruleBox").set_visible(False) builder.get_object("ruleBox").set_visible(False)
@@ -330,7 +327,7 @@ class Application:
def get_wanted_card_ids(self) -> List[str]: def get_wanted_card_ids(self) -> List[str]:
all_ids = [] all_ids = []
for cards in self.wants.values(): for cards in self.wants.values():
next_ids = [card.multiverse_id for card in cards] next_ids = [card['multiverse_id'] for card in cards]
all_ids = list(set(all_ids) | set(next_ids)) all_ids = list(set(all_ids) | set(next_ids))
return all_ids return all_ids
@@ -442,10 +439,7 @@ class Application:
def get_all_sets(self) -> dict: def get_all_sets(self) -> dict:
if not self.is_online(): if not self.is_online():
l = self.db.set_get_all() out = {s['code']: s for s in self.db.set_get_all()}
out = {}
for s in l:
out[s.code] = s
else: else:
out = util.load_sets(util.get_root_filename('sets')) out = util.load_sets(util.get_root_filename('sets'))
return out return out

View File

@@ -6,7 +6,6 @@ from cardvault import application
from gi.repository import Gtk, GdkPixbuf, Gdk from gi.repository import Gtk, GdkPixbuf, Gdk
from typing import Dict, Type from typing import Dict, Type
from mtgsdk import Card
import time import time
gi.require_version('Gtk', '3.0') gi.require_version('Gtk', '3.0')
@@ -14,7 +13,7 @@ gi.require_version('Gdk', '3.0')
class CardList(Gtk.ScrolledWindow): class CardList(Gtk.ScrolledWindow):
def __init__(self, filtered, app: 'application.Application', row_colors: Dict[str, str]): def __init__(self, filtered, app, row_colors: Dict[str, str]):
Gtk.ScrolledWindow.__init__(self) Gtk.ScrolledWindow.__init__(self)
self.set_hexpand(True) self.set_hexpand(True)
self.set_vexpand(True) self.set_vexpand(True)
@@ -49,7 +48,7 @@ class CardList(Gtk.ScrolledWindow):
output[card_id] = card output[card_id] = card
return output return output
def update(self, library: Dict[str, Type[Card]]): def update(self, library: Dict[str, dict]):
self.store.clear() self.store.clear()
if library is None: if library is None:
return return
@@ -63,22 +62,24 @@ class CardList(Gtk.ScrolledWindow):
all_wants = self.app.get_wanted_card_ids() all_wants = self.app.get_wanted_card_ids()
for card in library.values(): for card in library.values():
if card.multiverse_id is not None: if card['multiverse_id'] is not None:
color = self.get_row_color(card, self.app.library, all_wants, self.row_colors) color = self.get_row_color(card, self.app.library, all_wants, self.row_colors)
mana_cost = None if card.types.__contains__("Land") else self.app.get_mana_icons(card.mana_cost) mana_cost = None
item = [card.multiverse_id, if not card.get('types').__contains__("Land"):
card.name, mana_cost = self.app.get_mana_icons(card.get('mana_cost'))
" ".join(card.supertypes if card.supertypes else ""), item = [card['multiverse_id'],
" ".join(card.types), card['name'],
card.rarity, " ".join(card.get('supertypes') or ""),
card.power, " ".join(card.get('types') or ""),
card.toughness, card.get('rarity'),
", ".join(card.printings), card.get('power'),
card.get('toughness'),
", ".join(card.get('printings') or ""),
mana_cost, mana_cost,
card.cmc, card.get('cmc'),
card.set_name, card.get('set_name'),
color, color,
card.original_text] card.get('original_text')]
self.store.append(item) self.store.append(item)
end = time.time() end = time.time()
util.log("Time to build Table: " + str(round(end - start, 3)) + "s", util.LogLevel.Info) util.log("Time to build Table: " + str(round(end - start, 3)) + "s", util.LogLevel.Info)
@@ -103,9 +104,9 @@ class CardList(Gtk.ScrolledWindow):
@staticmethod @staticmethod
def get_row_color(card, lib: dict, wants: dict, colors: dict) -> str: def get_row_color(card, lib: dict, wants: dict, colors: dict) -> str:
if lib.__contains__(card.multiverse_id): if lib.__contains__(card.get('multiverse_id')):
return colors["owned"] return colors["owned"]
elif wants.__contains__(card.multiverse_id): elif wants.__contains__(card.get('multiverse_id')):
return colors["wanted"] return colors["wanted"]
else: else:
return colors["unowned"] return colors["unowned"]

Some files were not shown because too many files have changed in this diff Show More