Add cards to want lists from search view.

This commit is contained in:
luxick
2017-06-29 14:52:15 +02:00
parent 010e110c2c
commit e88fdbbf35
10 changed files with 230 additions and 169 deletions

View File

@@ -99,7 +99,7 @@ class Application:
window.set_title(card.name)
# Card Image
container = builder.get_object("imageContainer")
pixbuf = self.get_card_image(card, 63 * 5, 88 * 5)
pixbuf = util.load_card_image(card, 63 * 5, 88 * 5, self.image_cache)
image = Gtk.Image().new_from_pixbuf(pixbuf)
container.add(image)
# Name
@@ -110,7 +110,7 @@ class Application:
supertypes = " - " + " ".join(card.subtypes)
types = " ".join(card.types) + supertypes
builder.get_object("cardTypes").set_text(types)
# Rarity
# Rarityget_card_image
builder.get_object("cardRarity").set_text(card.rarity if card.rarity else "")
# Release
builder.get_object("cardReleaseDate").set_text(card.release_date if card.release_date else "")
@@ -339,16 +339,6 @@ class Application:
l.remove(card)
util.log("Removed '{}' from wants list '{}'".format(card.name, list), util.LogLevel.Info)
def get_card_image(self, card, sizex, sizey):
# Try using file from local cache, or load online
try:
pixbuf = self.image_cache[card.multiverse_id]
except KeyError as err:
util.log("No local image for " + card.name + ". Loading from " + card.image_url, util.LogLevel.Info)
pixbuf = util.load_card_image_online(card, sizex, sizey)
self.image_cache[card.multiverse_id] = pixbuf
return pixbuf
def get_mana_icons(self, mana_string):
if not mana_string:
util.log("No mana string provided", util.LogLevel.Warning)
@@ -371,5 +361,5 @@ class Application:
def main():
win = Application()
Application()
Gtk.main()

View File

@@ -12,15 +12,16 @@ gi.require_version('Gdk', '3.0')
class CardList(Gtk.ScrolledWindow):
def __init__(self, with_filter, app : 'application.Application'):
def __init__(self, filtered, app: 'application.Application', row_colors: Dict[str, str]):
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.filtered = filtered
self.lib = {}
self.app = app
self.row_colors = row_colors
# Columns are these:
# 0 Multiverse ID
@@ -127,34 +128,24 @@ class CardList(Gtk.ScrolledWindow):
output[card_id] = card
return output
def update(self, library: Dict[str, Type[Card]], colorize=False):
def update(self, library: Dict[str, Type[Card]]):
self.store.clear()
if library is None:
return
self.lib = library
# Disable update if tree is filtered (performance)
if self.filtered:
self.list.freeze_child_notify()
self.list.set_model(None)
util.log("Updating tree view", util.LogLevel.Info)
start = time.time()
all_wants = self.app.get_wanted_card_ids()
for card_id, card in library.items():
for card in library.values():
if card.multiverse_id is not None:
if self.app.library.__contains__(card_id) and colorize:
color = util.card_view_colors["owned"]
elif all_wants.__contains__(card_id) and colorize:
color = util.card_view_colors["wanted"]
else:
color = util.card_view_colors["unowned"]
if card.type == "Land":
mana_cost = None
else:
mana_cost = self.app.get_mana_icons(card.mana_cost)
color = self.get_row_color(card, self.app.library, all_wants, self.row_colors)
mana_cost = None if card.type == "Land" else self.app.get_mana_icons(card.mana_cost)
item = [card.multiverse_id,
card.name,
" ".join(card.supertypes if card.supertypes else ""),
@@ -169,15 +160,16 @@ class CardList(Gtk.ScrolledWindow):
color]
self.store.append(item)
end = time.time()
util.log("Time to build Table: " + str(round(end - start, 3)) + "s", util.LogLevel.Info)
util.log("Total entries: " + str(len(self.lib)), util.LogLevel.Info)
# Reactivate update for filtered trees
if self.filtered:
self.list.set_model(self.filter_and_sort)
self.list.thaw_child_notify()
def compare_rarity(self, model, row1, row2, user_data):
@staticmethod
def compare_rarity(model, row1, row2, user_data):
# Column for rarity
sort_column = 4
value1 = model.get_value(row1, sort_column)
@@ -189,4 +181,13 @@ class CardList(Gtk.ScrolledWindow):
else:
return 1
@staticmethod
def get_row_color(card, lib: dict, wants: dict, colors: dict) -> str:
if lib.__contains__(card.multiverse_id):
return colors["owned"]
elif wants.__contains__(card.multiverse_id):
return colors["wanted"]
else:
return colors["unowned"]

View File

@@ -9,10 +9,107 @@
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">False</property>
<property name="vexpand">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="row_spacing">5</property>
<property name="column_spacing">5</property>
<child>
<object class="GtkOverlay" id="imageContainer">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="ruleBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Rulings</property>
<attributes>
<attribute name="scale" value="1.2"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="height_request">200</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="GtkGrid" id="rulesGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">10</property>
<property name="column_spacing">20</property>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">3</property>
</packing>
</child>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
@@ -210,6 +307,30 @@
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="left_attach">1</property>
@@ -237,103 +358,6 @@
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkOverlay" id="imageContainer">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="ruleBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Rulings</property>
<attributes>
<attribute name="scale" value="1.2"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="height_request">200</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="GtkGrid" id="rulesGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">10</property>
<property name="column_spacing">20</property>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">start</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">3</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">

View File

@@ -7,10 +7,10 @@
<property name="can_focus">False</property>
<signal name="show" handler="search_tree_popup_showed" swapped="no"/>
<child>
<object class="GtkMenuItem" id="searchListPopupTags">
<object class="GtkMenuItem" id="searchListPopupWants">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Tag Cards</property>
<property name="label" translatable="yes">Add to Wants List</property>
<property name="use_underline">True</property>
</object>
</child>

View File

@@ -68,6 +68,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="placeholder_text" translatable="yes">New Wants List</property>
<signal name="activate" handler="on_new_wants_list_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>

View File

@@ -3,7 +3,6 @@ gi.require_version('Gtk', '3.0')
import datetime
import os
from gi.repository import Gtk
from typing import Type
from cardvault import lib_funct
from cardvault import search_funct
@@ -32,8 +31,9 @@ class Handlers:
if response == Gtk.ResponseType.OK:
# prepare export file
file = {"library": self.app.library, "tags": self.app.tags}
file = {"library": self.app.library, "tags": self.app.tags, "wants": self.app.wants}
util.export_library(dialog.get_filename(), file)
self.app.push_status("Library exported")
dialog.destroy()
@@ -54,9 +54,11 @@ class Handlers:
imports = util.import_library(dialog.get_filename())
self.app.library = imports[0]
self.app.tags = imports[1]
self.app.wants = imports[2]
# Cause current page to reload with imported data
self.app.current_page.emit('show')
self.app.unsaved_changes = True
self.app.push_status("Library imported")
dialog.destroy()
def on_view_changed(self, item):
@@ -90,7 +92,7 @@ class Handlers:
results = search_funct.search_cards(search_term, filters)
card_list = self.app.ui.get_object("searchResults").get_child()
card_list.update(results, colorize=True)
card_list.update(results)
self.app.ui.get_object("searchOverlay").set_visible(False)
@@ -111,12 +113,12 @@ class Handlers:
card_id = model.get_value(tree_iter, 0)
card = card_view.lib[card_id]
self.app.add_card_to_lib(card)
search_funct.reload_serach_view(self.app)
search_funct.reload_search_view(self.app)
self.app.ui.get_object("searchEntry").grab_focus()
def search_tree_popup_showed(self, menu):
# Create wants Submenu
wants_item = self.app.ui.get_object("searchListPopupTags")
wants_item = self.app.ui.get_object("searchListPopupWants")
wants_sub = Gtk.Menu()
wants_item.set_submenu(wants_sub)
@@ -125,7 +127,6 @@ class Handlers:
wants_sub.add(item)
item.set_label(list_name)
item.connect('activate', self.search_popup_add_wants)
wants_item.show_all()
def search_popup_add_wants(self, item):
@@ -134,7 +135,7 @@ class Handlers:
cards = card_list.get_selected_cards()
for card in cards.values():
self.app.add_card_to_want_list(item.get_label(), card)
search_funct.reload_serach_view(self.app)
search_funct.reload_search_view(self.app)
self.app.push_status("Added " + str(len(cards)) + " card(s) to Want List '" + item.get_label() + "'")
# ---------------------------------Library----------------------------------------------
@@ -255,6 +256,7 @@ class Handlers:
def on_new_wants_list_clicked(self, entry):
name = entry.get_text()
entry.set_text("")
# Check if list name already exists
if self.app.wants.__contains__(name):
return
@@ -271,7 +273,15 @@ class Handlers:
def do_wants_tree_press_event(self, treeview, event):
if event.button == 3: # right click
path = treeview.get_path_at_pos(int(event.x), int(event.y))
# Get the selection
selection = treeview.get_selection()
# Get the selected path(s)
rows = selection.get_selected_rows()
# If not clicked on selection, change selected rows
if path:
if path[0] not in rows[1]:
selection.unselect_all()
selection.select_path(path[0])
self.app.ui.get_object("wants_wantsListPopup").popup(None, None, None, None, 0, event.time)
return True
@@ -282,8 +292,9 @@ class Handlers:
tag = model.get_value(tree_iter, 0)
new_name = self.app.show_rename_dialog(tag)
self.app.rename_want_list(tag, new_name)
self.app.current_page.emit('show')
if not tag == new_name:
self.app.rename_want_list(tag, new_name)
self.app.current_page.emit('show')
def do_delete_wants_list(self, tree):
(model, pathlist) = tree.get_selection().get_selected_rows()
@@ -360,11 +371,12 @@ class Handlers:
# Get the selected path(s)
rows = selection.get_selected_rows()
# If not clicked on selection, change selected rows
if path[0] not in rows[1]:
selection.unselect_all()
selection.select_path(path[0])
self.app.ui.get_object("searchListPopup").emit('show')
self.app.ui.get_object("searchListPopup").popup(None, None, None, None, 0, event.time)
if path:
if path[0] not in rows[1]:
selection.unselect_all()
selection.select_path(path[0])
self.app.ui.get_object("searchListPopup").emit('show')
self.app.ui.get_object("searchListPopup").popup(None, None, None, None, 0, event.time)
return True
# ---------------------------------Library Tree----------------------------------------------

View File

@@ -1,13 +1,15 @@
from cardvault import cardlist
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from cardvault import util
from cardvault import cardlist
def init_library_view(app):
# Create Tree View for library
container = app.ui.get_object("libraryContainer")
card_list = cardlist.CardList(True, app)
card_list = cardlist.CardList(True, app, util.GENERIC_TREE_COLORS)
card_list.set_name("libScroller")
# Show details
card_list.list.connect("row-activated", app.handlers.on_library_card_selected)

View File

@@ -26,10 +26,10 @@ def init_search_view(app: 'application.Application'):
_init_results_tree(app)
def reload_serach_view(app: 'application.Application'):
def reload_search_view(app: 'application.Application'):
results_tree = app.ui.get_object("searchResults").get_child()
cards = results_tree.lib
results_tree.update(cards, True)
results_tree.update(cards)
def get_filters(app: 'application.Application') -> dict:
@@ -94,7 +94,7 @@ def search_cards(term: str, filters: dict) -> dict:
def _init_results_tree(app: 'application.Application'):
overlay = app.ui.get_object("searchResults")
card_list = cardlist.CardList(False, app)
card_list = cardlist.CardList(False, app, util.SEARCH_TREE_COLORS)
card_list.set_name("resultsScroller")
card_list.list.connect("row-activated", app.handlers.on_search_card_selected)
card_list.selection.connect("changed", app.handlers.on_search_selection_changed)

View File

@@ -32,6 +32,21 @@ START_PAGE = "search"
LOG_LEVEL = 1
# Colors for card rows in search view
SEARCH_TREE_COLORS ={
"unowned": "black",
"wanted": "#D39F30",
"owned": "#62B62F"
}
# Colors for card rows in every default view
GENERIC_TREE_COLORS ={
"unowned": "black",
"wanted": "black",
"owned": "black"
}
default_config = {
"hide_duplicates_in_search": False,
"start_page": "search",
@@ -49,12 +64,6 @@ legality_colors ={
"Legal": "#62B62F"
}
card_view_colors ={
"unowned": "black",
"wanted": "#D39F30",
"owned": "#62B62F"
}
rarity_dict = {
"special": 0,
"common": 1,
@@ -126,7 +135,7 @@ def reload_image_cache(path: str) -> dict:
pixbuf = GdkPixbuf.Pixbuf.new_from_file(path + imagefile)
# Strip filename extension
imagename = os.path.splitext(imagefile)[0]
cache[imagename] = pixbuf
cache[int(imagename)] = pixbuf
except OSError as err:
log("Error loading image: " + str(err), LogLevel.Error)
except GLib.GError as err:
@@ -172,14 +181,22 @@ def load_mana_icons(path: str) -> dict:
return icons
def net_load_set_list() -> dict:
""" Load the list of all MTG sets from the Gather"""
try:
sets = Set.all()
except MtgException as err:
log(str(err), LogLevel.Error)
return {}
return sets
def load_sets(filename: str) -> dict:
if not os.path.isfile(filename):
# TODO Update Data function
# if not os.path.isfile(filename):
if True:
# use mtgsdk api to retrieve al list of all sets
try:
sets = Set.all()
except MtgException as err:
log(str(err), LogLevel.Error)
return {}
sets = net_load_set_list()
# Serialize the loaded data to a file
pickle.dump(sets, open(filename, 'wb'))
# Deserialize set data from local file
@@ -209,13 +226,15 @@ def import_library(path: str) -> ():
try:
library = imported["library"]
tags = imported["tags"]
wants = imported["wants"]
except KeyError as err:
log("Invalid library format " + str(err), LogLevel.Error)
library = {}
tags = {}
wants = {}
log("Library imported", LogLevel.Info)
return library, tags
return library, tags, wants
def save_file(path, file):
@@ -245,14 +264,25 @@ def load_dummy_image(size_x: int, size_y: int) -> GdkPixbuf:
+ '/resources/images/dummy.jpg', size_x, size_y)
def load_card_image_online(card, size_x: int, size_y: int) -> GdkPixbuf:
def load_card_image(card: 'mtgsdk.Card', size_x: int, size_y: int, cache: dict) -> GdkPixbuf:
""" Retrieve an card image from cache or alternatively load from gatherer"""
try:
image = cache[card.multiverse_id]
except KeyError as err:
log("No local image for " + card.name + ". Loading from " + card.image_url, LogLevel.Info)
filename, image = net_load_card_image(card, size_x, size_y)
cache[card.multiverse_id] = image
return image
def net_load_card_image(card, size_x: int, size_y: int) -> (str, GdkPixbuf):
url = card.image_url
if url is None:
log("No Image URL for " + card.name, LogLevel.Warning)
return load_dummy_image(size_x, size_y)
filename = IMAGE_CACHE_PATH + str(card.multiverse_id) + ".png"
request.urlretrieve(url, filename)
return GdkPixbuf.Pixbuf.new_from_file_at_size(filename, size_x, size_y)
return filename, GdkPixbuf.Pixbuf.new_from_file_at_size(filename, size_x, size_y)
def create_mana_icons(icons: dict, mana_string: str) -> GdkPixbuf:

View File

@@ -4,13 +4,14 @@ from gi.repository import Gtk
from cardvault import cardlist
from cardvault import application
from cardvault import util
def init_wants_view(app: 'application.Application'):
# Get container for Cardlist Tree
container = app.ui.get_object("wantsListContainer")
# Create new Cardlist
card_list = cardlist.CardList(True, app)
card_list = cardlist.CardList(True, app, util.GENERIC_TREE_COLORS)
card_list.set_name("wantsScroller")
# Show details
card_list.list.connect("row-activated", app.handlers.on_wants_card_selected)