diff --git a/.gitignore b/.gitignore
index 50633dc..a781a70 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,9 @@
-fonts
+domdiv/fonts/*.otf
+domdiv/fonts/*.ttf
*.pdf
*.pyc
generated
-dominiontabs.egg-info
+*.egg-info
build
dist
*~
diff --git a/.project b/.project
deleted file mode 100644
index 81b67a2..0000000
--- a/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
- domtabs
-
-
-
-
-
- org.python.pydev.PyDevBuilder
-
-
-
-
-
- org.python.pydev.pythonNature
-
-
diff --git a/.pydevproject b/.pydevproject
deleted file mode 100644
index 22d91c4..0000000
--- a/.pydevproject
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-/domtabs
-
-python 2.7
-venv_default
-
diff --git a/MANIFEST.in b/MANIFEST.in
index dfc47a1..924270d 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,3 +1,4 @@
-include card_db/*/*.json
-include images/*.png
+recursive-include domdiv/card_db *.json
+include domdiv/images/*.png
+include domdiv/fonts/*.ttf
diff --git a/README.md b/README.md
index 2f5eb89..5256310 100644
--- a/README.md
+++ b/README.md
@@ -4,21 +4,33 @@
## Introduction
-This is a script to generate card dividers for storing cards for the game [Dominion](https://boardgamegeek.com/boardgame/36218/dominion). If you are just looking go generate some dominion dividers, there is no need to install this script as I host a [live version of this generator code](http://domtabs.sandflea.org). However, if you want to use arguments that I don't expose on that page, or change the code, or contribute to the project the full generation code (not the web interface or the fonts) is included here, and contributions are more than welcome.
+This is a script and library to generate card dividers for storing cards for the game [Dominion](https://boardgamegeek.com/boardgame/36218/dominion). If you are just looking go generate some dominion dividers, there is no need to install this script as I host a [live version of this generator code](http://domtabs.sandflea.org). However, if you want to use arguments that I don't expose on that page, or change the code, or contribute to the project the full generation code (not the web interface or the fonts) is included here, and contributions are more than welcome.
Again, to generate tabs go to the ***[Online Generator](http://domtabs.sandflea.org)***.
-## Prerequisites
-
-#### Python Packages
-You need the python packages for reportlab (http://www.reportlab.com/software/opensource/rl-toolkit/download/) and PIL (http://www.pythonware.com/products/pil/) installed. You can install them manually or use the included setup.py via 'python setup.py install' (perhaps run via 'sudo' if not in a virtual env) which should install everything for you.
-
-#### Fonts
-I believe I cannot distribute one font (Minion Pro) dominion\_tabs uses as they are commercially sold by Adobe. However, the font files are included with every install of the free Adobe Reader. For example, on Windows 7 they are in C:\Program Files (x86)\Adobe\Reader 9.0\Resource\Font called `MinionPro-Regular.otf`, `MinionPro-Bold.otf` and `MinionPro-It.otf`.
-
-Sadly, these fonts use features of the otf format that are not support by the reportlab package. Thus, they need to first be converted to ttf (TrueType) format. I used the open source package fontforge to do the conversion. Included as 'convert.ff' is a script for fontforge to do the conversion, on Mac OS X with fontforge installed through macports you can just run `./convert.ff MinionPro-Regular.otf`, `./convert.ff MinionPro-Bold.otf` and `./convert.ff MinionPro-It.otf`. With other fontforge installations, you'll need to change the first line of convert.ff to point to your fontforge executable. I have not done this step under Windows - I imagine it may be possible with a cygwin install of fontforge or some such method. Copy these converted files to a subdirectory called `fonts` in the dominion_tabs directory.
-
+## Prerequisites
+
+#### Python Packages
+You need the python packages for reportlab (http://www.reportlab.com/software/opensource/rl-toolkit/download/) and PIL (http://www.pythonware.com/products/pil/) installed. You can install them manually or use the included setup.py via 'python setup.py install' (perhaps run via 'sudo' if not in a virtual env) which should install everything for you.
+
+#### Fonts
+I believe I cannot distribute one font (Minion Pro) domdiv uses as they are owned by Adobe with a License that I understand to disallow redistribution.
+
+However, it appears you can download them here:
+- http://fontsgeek.com/fonts/Minion-Pro-Regular
+- http://fontsgeek.com/fonts/Minion-Pro-Italic
+- http://fontsgeek.com/fonts/Minion-Pro-Bold
+
+Alternatively, the font files are included with every install of the free Adobe Reader. For example, on Windows 7 they are in C:\Program Files (x86)\Adobe\Reader 9.0\Resource\Font called `MinionPro-Regular.otf`, `MinionPro-Bold.otf` and `MinionPro-It.otf`.
+
+Sadly, all these fonts use features that are not support by the reportlab package. Thus, they need to first be converted to ttf (TrueType) format. I used the open source package fontforge to do the conversion. Included as 'convert.ff' is a script for fontforge to do the conversion, on Mac OS X with fontforge installed through macports or homebrew you can just run `./convert.ff MinionPro-Regular.otf`, `./convert.ff MinionPro-Bold.otf` and `./convert.ff MinionPro-It.otf`. With other fontforge installations, you'll need to change the first line of convert.ff to point to your fontforge executable. I have not done this step under Windows - I imagine it may be possible with a cygwin install of fontforge or some such method.
+
+Copy the converted `.ttf` files to the `fonts` directory in the `domdiv` package/directory, then perform the package install below.
+
## Install/Running
-Once the prerequisites exist, just run `python dominion_dividers.py ` to produce a pdf file of dominion tabs. You can use a `-h` flag to see various options, such as changing to vertical tabs.
-
-Feel free to comment on boardgamegeek at or file issues on github ().
+Run `python setup.py install`. This should install the needed prerequisites and make a script called `dominion_dividers` available in your python script directory. Run `dominion_dividers ` to get a pdf of all dividers with the default options, or run `dominion_dividers --help` to see the (extensive) list of options.
+
+## Using as a library
+The library will be installed as `domdiv` with the main entry point being `domdiv.main.generate(options)`. It takes a `Namespace` of options as generated by python's `argparser` module. You can either use `domdiv.main.parse_opts(cmdline_args)` to get such an object by passing in a list of command line options (like `sys.argv`), or directly create an appropriate object by assigning the correct values to its attributes, starting from an empty class or an actual argparse `Namespace` object.
+
+Feel free to comment on boardgamegeek at or file issues on github ().
diff --git a/__init__.py b/__init__.py
deleted file mode 100644
index 184e5e1..0000000
--- a/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# main package
-
-__version__ = '2.2'
diff --git a/domdiv/__init__.py b/domdiv/__init__.py
index 4ec9592..2b9ccf1 100644
--- a/domdiv/__init__.py
+++ b/domdiv/__init__.py
@@ -1,1043 +1 @@
-import os
-import codecs
-import json
-import sys
-import argparse
-import copy
-
-import reportlab.lib.pagesizes as pagesizes
-from reportlab.lib.units import cm
-
-from cards import Card
-from cards import CardType
-from draw import DividerDrawer
-
-LOCATION_CHOICES = ["tab", "body-top", "hide"]
-NAME_ALIGN_CHOICES = ["left", "right", "centre", "edge"]
-TAB_SIDE_CHOICES = ["left", "right", "left-alternate", "right-alternate",
- "centre", "full"]
-TEXT_CHOICES = ["card", "rules", "blank"]
-EDITION_CHOICES = ["1", "2", "latest", "all"]
-
-EXPANSION_CHOICES = ["adventures", "alchemy", "cornucopia", "dark ages",
- "dominion1stEdition", "dominion2ndEdition", "dominion2ndEditionUpgrade",
- "empires", "guilds", "hinterlands",
- "intrigue1stEdition", "intrigue2ndEdition", "intrigue2ndEditionUpgrade",
- "promo", "prosperity", "seaside"]
-
-LANGUAGE_DEFAULT = 'en_us' # the primary language used if a language's parts are missing
-LANGUAGE_XX = 'xx' # a dummy language for starting translations
-
-
-def get_languages(path):
- languages = []
- for name in os.listdir(path):
- dir_path = os.path.join(path, name)
- if os.path.isdir(dir_path):
- cards_file = os.path.join(dir_path, "cards_" + name + ".json")
- sets_file = os.path.join(dir_path, "sets_" + name + ".json")
- types_file = os.path.join(dir_path, "types_" + name + ".json")
- if (os.path.isfile(cards_file) and os.path.isfile(sets_file) and os.path.isfile(types_file)):
- languages.append(name)
- if LANGUAGE_XX in languages:
- languages.remove(LANGUAGE_XX)
- return languages
-
-
-LANGUAGE_CHOICES = get_languages("card_db")
-
-
-def add_opt(options, option, value):
- assert not hasattr(options, option)
- setattr(options, option, value)
-
-
-def parse_opts(arglist):
- parser = argparse.ArgumentParser(
- formatter_class=argparse.ArgumentDefaultsHelpFormatter,
- description="Generate Dominion Dividers",
- epilog="Source can be found at 'https://github.com/sumpfork/dominiontabs'. "
- "An online version can be found at 'http://domtabs.sandflea.org/'. ")
-
- # Basic Divider Information
- group_basic = parser.add_argument_group(
- 'Basic Divider Options',
- 'Basic choices for the dividers.')
- group_basic.add_argument(
- '--outfile', '-o',
- dest="outfile",
- default="dominion_dividers.pdf",
- help="The output file name.")
- group_basic.add_argument(
- "--papersize",
- dest="papersize",
- default=None,
- help="The size of paper to use; '<%%f>x<%%f>' (size in cm), or 'A4', or 'LETTER'. "
- "If not specified, it will default to system defaults, and if the system defaults "
- "are not found, then to 'LETTER'.")
- group_basic.add_argument(
- "--language", "-l",
- dest="language",
- default=LANGUAGE_DEFAULT,
- choices=LANGUAGE_CHOICES,
- help="Language of divider text.")
- group_basic.add_argument(
- "--orientation",
- choices=["horizontal", "vertical"],
- dest="orientation",
- default="horizontal",
- help="Either horizontal or vertical divider orientation.")
- group_basic.add_argument(
- "--size",
- dest="size",
- default='normal',
- help="Dimentions of the cards to use with the dividers '<%%f>x<%%f>' (size in cm), "
- "or 'normal' = '9.1x5.9', or 'sleeved' = '9.4x6.15'.")
- group_basic.add_argument(
- "--sleeved",
- action="store_true",
- dest="sleeved",
- help="Same as --size=sleeved.")
- group_basic.add_argument(
- "--order",
- choices=["expansion", "global", "colour", "cost"],
- default="expansion",
- dest="order",
- help="Sort order for the dividers: "
- " 'global' will sort by card name;"
- " 'expansion' will sort by expansion, then card name;"
- " 'colour' will sort by card type, then card name;"
- " 'cost' will sort by expansion, then card cost, then name.")
-
- # Divider Body
- group_body = parser.add_argument_group(
- 'Divider Body',
- 'Changes what is displayed on the body of the dividers.')
- group_body.add_argument(
- "--front",
- choices=TEXT_CHOICES,
- dest="text_front",
- default="card",
- help="Text to print on the front of the divider; "
- "'card' will print the text from the game card; "
- "'rules' will print additional rules for the game card; "
- "'blank' will not print text on the divider.")
- group_body.add_argument(
- "--back",
- choices=TEXT_CHOICES + ["none"],
- dest="text_back",
- default="rules",
- help="Text to print on the back of the divider; "
- "'card' will print the text from the game card; "
- "'rules' will print additional rules for the game card; "
- "'blank' will not print text on the divider; "
- "'none' will prevent the back pages from printing. ")
- group_body.add_argument(
- "--count",
- action="store_true",
- dest="count",
- help="Display card count on body of the divider.")
- group_body.add_argument(
- "--types",
- action="store_true",
- dest="types",
- help="Display card type on the body of the divider.")
-
- # Divider Tab
- group_tab = parser.add_argument_group(
- 'Divider Tab',
- 'Changes what is displayed on on the Divider Tab.')
- group_tab.add_argument(
- "--tab_side",
- choices=TAB_SIDE_CHOICES,
- dest="tab_side",
- default="right-alternate",
- help="Alignment of tab; "
- "'left'/'right' forces all tabs to left/right side; "
- "'left-alternate' will start on the left and then toggle between left and right for the tabs; "
- "'right-alternate' will start on the right and then toggle between right and left for the tabs; "
- "'centre' will force all label tabs to the centre; "
- "'full' will force all label tabs to be full width of the divider.")
- group_tab.add_argument(
- "--tab_name_align",
- choices=NAME_ALIGN_CHOICES + ["center"],
- dest="tab_name_align",
- default="left",
- help="Alignment of text on the tab; "
- "The 'edge' option will align the card name to the outside edge of the "
- "tab, so that when using tabs on alternating sides, "
- "the name is less likely to be hidden by the tab in front "
- "(edge will revert to left when tab_side is full since there is no edge in that case).")
- group_tab.add_argument(
- "--tabwidth",
- type=float,
- default=4.0,
- help="Width in cm of stick-up tab (ignored if --tab_side is 'full' or --tabs_only is used).")
- group_tab.add_argument(
- "--cost",
- action="append",
- choices=LOCATION_CHOICES,
- default=['tab'],
- help="Where to display the card cost; may be set to "
- "'hide' to indicate it should not be displayed, or "
- "given multiple times to show it in multiple places.")
- group_tab.add_argument(
- "--set_icon",
- action="append",
- choices=LOCATION_CHOICES,
- default=['tab'],
- help="Where to display the set icon; may be set to "
- "'hide' to indicate it should not be displayed, or "
- "given multiple times to show it in multiple places.")
- group_tab.add_argument(
- "--no-tab-artwork",
- action="store_true",
- dest="no_tab_artwork",
- help="Don't show background artwork on tabs.")
- group_tab.add_argument(
- "--use-text-set-icon",
- action="store_true",
- dest="use_text_set_icon",
- help="Use text/letters to represent a card's set instead of the set icon.")
-
- # Expanion Dividers
- group_expansion = parser.add_argument_group(
- 'Expansion Dividers',
- 'Adding separator dividers for each expansion.')
- group_expansion.add_argument(
- "--expansion_dividers",
- action="store_true",
- dest="expansion_dividers",
- help="Add dividers describing each expansion set. "
- "A list of cards in the expansion will be shown on the front of the divider.")
- group_expansion.add_argument(
- "--centre_expansion_dividers",
- action="store_true",
- dest="centre_expansion_dividers",
- help='Centre the tabs on expansion dividers.')
- group_expansion.add_argument(
- "--expansion_dividers_long_name",
- action="store_true",
- dest="expansion_dividers_long_name",
- help="Use the long name with edition information on the expansion divider tab. "
- "Without this, the shorter expansion name is used on the expansion divider tab.")
-
- # Divider Selection
- group_select = parser.add_argument_group(
- 'Divider Selection',
- 'What expansions are used, and grouping of dividers.')
- group_select.add_argument(
- "--expansions", "--expansion",
- nargs="*",
- action="append",
- dest="expansions",
- help="Limit dividers to only the specified expansions. "
- "If no limits are set, then all expansions are included. "
- "Expansion names can also be given in the language specified by "
- "the --language parameter. Any expansion with a space in the name must "
- "be enclosed in quotes. This may be called multiple times. "
- "Values are not case sensitive and can also match the starting characters "
- "of an expansion name. For example, 'dominion' will match all expansions "
- "that start with that name; Choices available in all languages include: %s" %
- ", ".join("%s" % x for x in EXPANSION_CHOICES))
- group_select.add_argument(
- "--edition",
- choices=EDITION_CHOICES,
- dest="edition",
- default="all",
- help="Editions to include: "
- "'1' is for all 1st Editions; "
- "'2' is for all 2nd Editions; "
- "'latest' is for the latest edition for each expansion; "
- "'all' is for all editions of expansions; "
- " This can be combined with other options to refine the expansions to include in the output.")
- group_select.add_argument(
- "--upgrade_with_expansion",
- action="store_true",
- dest="upgrade_with_expansion",
- help="Include any new edition upgrade cards with the expansion being upgraded.")
- group_select.add_argument(
- "--base_cards_with_expansion",
- action="store_true",
- help="Print the base cards as part of the expansion (i.e., a divider for 'Silver' "
- "will be printed as both a 'Dominion' card and as an 'Intrigue 1st Edition' card). "
- "If this option is not given, all base cards are placed in their own 'Base' expansion.")
- group_select.add_argument(
- "--special_card_groups",
- action="store_true",
- help="Group cards that generally are used together "
- "(e.g., Shelters, Tournament and Prizes, Urchin/Mercenary, etc.).")
- group_select.add_argument(
- "--include_blanks",
- action="store_true",
- help="Include a few dividers with extra text.")
- group_select.add_argument(
- "--exclude_events",
- action="store_true",
- help="Group all 'Event' cards across all expansions into one divider.")
- group_select.add_argument(
- "--exclude_landmarks",
- action="store_true",
- help="Group all 'Landmark' cards across all expansions into one divider.")
-
- # Divider Sleeves/Wrappers
- group_wrapper = parser.add_argument_group(
- 'Card Sleeves/Wrappers',
- 'Generating dividers that are card sleeves/wrappers.')
- group_wrapper.add_argument(
- "--wrapper",
- action="store_true",
- dest="wrapper",
- help="Draw sleeves (aka wrapper) for the cards instead of a divider for the cards.")
- group_wrapper.add_argument(
- "--thickness",
- type=float,
- default=2.0,
- help="Thickness of a stack of 60 cards (Copper) in centimeters. "
- "Typically unsleeved cards are 2.0, thin sleeved cards are 2.4, and thick sleeved cards are 3.2. "
- "This is only valid with the --wrapper option.")
- group_wrapper.add_argument(
- "--sleeved_thick",
- action="store_true",
- dest="sleeved_thick",
- help="Same as --size=sleeved --thickness 3.2.")
- group_wrapper.add_argument(
- "--sleeved_thin",
- action="store_true",
- dest="sleeved_thin",
- help="Same as --size=sleeved --thickness 2.4.")
- group_wrapper.add_argument(
- "--notch_length",
- type=float,
- default=0.0,
- help="Length of thumb notch on wrapper in centimeters "
- "(a value of 0.0 means no notch on wrapper). "
- "This can make it easier to remove the actual cards from the wrapper. "
- "This is only valid with the --wrapper option.")
- group_wrapper.add_argument(
- "--notch",
- action="store_true",
- dest="notch",
- help="Same as --notch_length thickness 1.5.")
-
- # Printing
- group_printing = parser.add_argument_group(
- 'Printing',
- 'Changes how the Dividers are printed.')
- group_printing.add_argument(
- "--minmargin",
- dest="minmargin",
- default="1x1",
- help="Page margin in cm in the form '<%%f>x<%%f>', left/right x top/bottom).")
- group_printing.add_argument(
- "--cropmarks",
- action="store_true",
- dest="cropmarks",
- help="Print crop marks on both sides, rather than tab outlines on the front side.")
- group_printing.add_argument(
- "--linewidth",
- type=float,
- default=0.1,
- help="Width of lines for card outlines and crop marks.")
- group_printing.add_argument(
- "--back_offset",
- type=float,
- dest="back_offset",
- default=0,
- help="Back page horizontal offset points to shift to the right. Only needed for some printers.")
- group_printing.add_argument(
- "--back_offset_height",
- type=float,
- dest="back_offset_height",
- default=0,
- help="Back page vertical offset points to shift upward. Only needed for some printers.")
- group_printing.add_argument(
- "--vertical_gap",
- type=float,
- default=0.0,
- help="Vertical gap between dividers in centimeters.")
- group_printing.add_argument(
- "--horizontal_gap",
- type=float,
- default=0.0,
- help="Horizontal gap between dividers in centimeters.")
- group_printing.add_argument(
- "--no-page-footer",
- action="store_true",
- dest="no_page_footer",
- help="Do not print the expansion name at the bottom of the page.")
- group_printing.add_argument(
- "--num_pages",
- type=int,
- default=-1,
- help="Stop generating dividers after this many pages, -1 for all.")
- group_printing.add_argument(
- "--tabs-only",
- action="store_true",
- dest="tabs_only",
- help="Draw only the divider tabs and no divider outlines. "
- "Used to print the divider tabs on labels.")
-
- # Special processing
- group_special = parser.add_argument_group(
- 'Miscellaneous',
- 'These options are generally not used.')
- group_special.add_argument(
- "--cardlist",
- dest="cardlist",
- help="Path to file that enumerates each card to be printed on its own line.")
- group_special.add_argument(
- "--write_json",
- action="store_true",
- dest="write_json",
- help="Write json version of card definitions and extras.")
-
- options = parser.parse_args(arglist)
-
- if options.sleeved_thick:
- options.thickness = 3.2
- options.sleeved = True
-
- if options.sleeved_thin:
- options.thickness = 2.4
- options.sleeved = True
-
- if options.notch:
- options.notch_length = 1.5
-
- if options.expansions:
- # options.expansions is a list of lists. Reduce to single list
- options.expansions = [item for sublist in options.expansions for item in sublist]
-
- return options
-
-
-def parseDimensions(dimensionsStr):
- x, y = dimensionsStr.upper().split('X', 1)
- return (float(x) * cm, float(y) * cm)
-
-
-def generate_sample(options):
- import cStringIO
- from wand.image import Image
- buf = cStringIO.StringIO()
- options.num_pages = 1
- generate(options, '.', buf)
- with Image(blob=buf.getvalue()) as sample:
- sample.format = 'png'
- sample.save(filename='sample.png')
-
-
-def parse_papersize(spec):
- papersize = None
- if not spec:
- if os.path.exists("/etc/papersize"):
- papersize = open("/etc/papersize").readline().upper()
- else:
- papersize = 'LETTER'
- else:
- papersize = spec.upper()
-
- try:
- paperwidth, paperheight = getattr(pagesizes, papersize)
- except AttributeError:
- try:
- paperwidth, paperheight = parseDimensions(papersize)
- print 'Using custom paper size, %.2fcm x %.2fcm' % (
- paperwidth / cm, paperheight / cm)
- except ValueError:
- paperwidth, paperheight = pagesizes.LETTER
- return paperwidth, paperheight
-
-
-def parse_cardsize(spec, sleeved):
- spec = spec.upper()
- if spec == 'SLEEVED' or sleeved:
- dominionCardWidth, dominionCardHeight = (9.4 * cm, 6.15 * cm)
- print 'Using sleeved card size, %.2fcm x %.2fcm' % (
- dominionCardWidth / cm, dominionCardHeight / cm)
- elif spec in ['NORMAL', 'UNSLEEVED']:
- dominionCardWidth, dominionCardHeight = (9.1 * cm, 5.9 * cm)
- print 'Using normal card size, %.2fcm x%.2fcm' % (
- dominionCardWidth / cm, dominionCardHeight / cm)
- else:
- dominionCardWidth, dominionCardHeight = parseDimensions(spec)
- print 'Using custom card size, %.2fcm x %.2fcm' % (
- dominionCardWidth / cm, dominionCardHeight / cm)
- return dominionCardWidth, dominionCardHeight
-
-
-def read_write_card_data(options):
-
- # Read in the card types
- types_db_filepath = os.path.join(options.data_path, "card_db", "types_db.json")
- with codecs.open(types_db_filepath, "r", "utf-8") as typefile:
- Card.types = json.load(typefile, object_hook=CardType.decode_json)
- assert Card.types, "Could not load any card types from database"
-
- # extract unique types
- type_list = []
- for c in Card.types:
- type_list = list(set(c.getTypeNames()) | set(type_list))
- # set up the basic type translation. The actual language will be added later.
- Card.type_names = {}
- for t in type_list:
- Card.type_names[t] = t
-
- # turn Card.types into a dictionary for later
- Card.types = dict(((c.getTypeNames(), c) for c in Card.types))
-
- # Read in the card database
- card_db_filepath = os.path.join(options.data_path, "card_db", "cards_db.json")
- with codecs.open(card_db_filepath, "r", "utf-8") as cardfile:
- cards = json.load(cardfile, object_hook=Card.decode_json)
- assert cards, "Could not load any cards from database"
-
- set_db_filepath = os.path.join(options.data_path, "card_db", "sets_db.json")
- with codecs.open(set_db_filepath, "r", "utf-8") as setfile:
- Card.sets = json.load(setfile)
- assert Card.sets, "Could not load any sets from database"
- for s in Card.sets:
- if 'no_randomizer' not in Card.sets[s]:
- Card.sets[s]['no_randomizer'] = False
-
- # Set cardset_tag and expand cards that are used in multiple sets
- new_cards = []
- for card in cards:
- sets = list(card.cardset_tags)
- if len(sets) > 0:
- # Set and save the first one
- card.cardset_tag = sets.pop(0)
- new_cards.append(card)
- for s in sets:
- # for the rest, create a copy of the first
- if s:
- new_card = copy.deepcopy(card)
- new_card.cardset_tag = s
- new_cards.append(new_card)
- cards = new_cards
-
- # Make sure each card has the right image file.
- for card in cards:
- card.image = card.setImage()
-
- if options.write_json:
- fpath = "cards.json"
- with codecs.open(fpath, 'w', encoding='utf-8') as ofile:
- json.dump(cards,
- ofile,
- cls=Card.CardJSONEncoder,
- ensure_ascii=False,
- indent=True,
- sort_keys=True)
- return cards
-
-
-class CardSorter(object):
- def __init__(self, order, baseCards):
- self.order = order
- if order == "global":
- self.sort_key = self.by_global_sort_key
- elif order == "colour":
- self.sort_key = self.by_colour_sort_key
- elif order == "cost":
- self.sort_key = self.by_cost_sort_key
- else:
- self.sort_key = self.by_expansion_sort_key
-
- self.baseCards = baseCards
-
- # When sorting cards, want to always put "base" cards after all
- # kingdom cards, and order the base cards in a set order - the
- # order they are listed in the database (ie, all normal treasures
- # by worth, then potion, then all normal VP cards by worth, then
- # trash)
- def baseIndex(self, name):
- try:
- return self.baseCards.index(name)
- except Exception:
- return -1
-
- def isBaseExpansionCard(self, card):
- return card.cardset.lower() != 'base' and card.name in self.baseCards
-
- def by_global_sort_key(self, card):
- return int(card.isExpansion()), self.baseIndex(card.name), card.name
-
- def by_expansion_sort_key(self, card):
- return card.cardset, int(card.isExpansion()), self.baseIndex(
- card.name), card.name
-
- def by_colour_sort_key(self, card):
- return card.getType().getTypeNames(), card.name
-
- def by_cost_sort_key(self, card):
- return card.cardset, int(card.isExpansion()), card.get_total_cost(card), card.name
-
- def __call__(self, card):
- return self.sort_key(card)
-
-
-def add_card_text(options, cards, language='en_us'):
- language = language.lower()
- # Read in the card text file
- card_text_filepath = os.path.join(options.data_path,
- "card_db",
- language,
- "cards_" + language.lower() + ".json")
- with codecs.open(card_text_filepath, 'r', 'utf-8') as card_text_file:
- card_text = json.load(card_text_file)
- assert language, "Could not load card text for %r" % language
-
- # Now apply to all the cards
- for card in cards:
- if card.card_tag in card_text:
- if 'name' in card_text[card.card_tag].keys():
- card.name = card_text[card.card_tag]['name']
- if 'description' in card_text[card.card_tag].keys():
- card.description = card_text[card.card_tag]['description']
- if 'extra' in card_text[card.card_tag].keys():
- card.extra = card_text[card.card_tag]['extra']
- return cards
-
-
-def add_set_text(options, sets, language='en_us'):
- language = language.lower()
- # Read in the set text and store for later
- set_text_filepath = os.path.join(options.data_path,
- "card_db",
- language,
- "sets_" + language + ".json")
- with codecs.open(set_text_filepath, 'r', 'utf-8') as set_text_file:
- set_text = json.load(set_text_file)
- assert set_text, "Could not load set text for %r" % language
-
- # Now apply to all the sets
- for s in sets:
- if s in set_text:
- for key in set_text[s]:
- sets[s][key] = set_text[s][key]
- return sets
-
-
-def add_type_text(options, types={}, language='en_us'):
- language = language.lower()
- # Read in the type text and store for later
- type_text_filepath = os.path.join(options.data_path,
- "card_db",
- language,
- "types_" + language + ".json")
- with codecs.open(type_text_filepath, 'r', 'utf-8') as type_text_file:
- type_text = json.load(type_text_file)
- assert type_text, "Could not load type text for %r" % language
-
- # Now apply to all the types
- used = {}
- for type in types:
- if type in type_text:
- types[type] = type_text[type]
- used[type] = True
-
- for type in type_text:
- if type not in used:
- types[type] = type_text[type]
-
- return types
-
-
-def add_bonus_regex(options, language='en_us'):
- language = language.lower()
- # Read in the bonus regex terms
- bonus_regex_filepath = os.path.join(options.data_path,
- "card_db",
- language,
- "bonuses_" + language + ".json")
- with codecs.open(bonus_regex_filepath, 'r', 'utf-8') as bonus_regex_file:
- bonus_regex = json.load(bonus_regex_file)
- assert bonus_regex, "Could not load bonus keywords for %r" % language
-
- if not bonus_regex:
- bonus_regex = {}
-
- return bonus_regex
-
-
-def combine_cards(cards, old_card_type, new_card_tag, new_cardset_tag, new_type):
-
- holder = Card(name='*Replace Later*',
- card_tag=new_card_tag,
- group_tag=new_card_tag,
- cardset_tag=new_cardset_tag,
- types=(new_type, ),
- count=0)
- holder.image = holder.setImage()
-
- filteredCards = []
- for c in cards:
- if c.isType(old_card_type):
- holder.addCardCount(c.count) # keep track of count and skip card
- else:
- filteredCards.append(c) # Not the right type, keep card
-
- if holder.getCardCount() > 0:
- filteredCards.append(holder)
-
- return filteredCards
-
-
-def filter_sort_cards(cards, options):
-
- # Filter out cards by edition
- if options.edition and options.edition != "all":
- keep_sets = []
- for set_tag in Card.sets:
- for edition in Card.sets[set_tag]["edition"]:
- if options.edition == edition:
- keep_sets.append(set_tag)
-
- keep_cards = [] # holds the cards that are to be kept
- for card in cards:
- if card.cardset_tag in keep_sets:
- keep_cards.append(card)
-
- cards = keep_cards
-
- # Combine upgrade cards with their expansion
- if options.upgrade_with_expansion:
- for card in cards:
- if card.cardset_tag == 'dominion2ndEditionUpgrade':
- card.cardset_tag = 'dominion1stEdition'
- elif card.cardset_tag == 'intrigue2ndEditionUpgrade':
- card.cardset_tag = 'intrigue1stEdition'
-
- # Combine all Events across all expansions
- if options.exclude_events:
- cards = combine_cards(cards,
- old_card_type="Event",
- new_type="Events",
- new_card_tag='events',
- new_cardset_tag='extras'
- )
- if options.expansions:
- options.expansions.append("extras")
-
- # Combine all Landmarks across all expansions
- if options.exclude_landmarks:
- cards = combine_cards(cards,
- old_card_type="Landmark",
- new_type="Landmarks",
- new_card_tag='landmarks',
- new_cardset_tag='extras'
- )
- if options.expansions:
- options.expansions.append("extras")
-
- # FIX THIS: Combine all Prizes across all expansions
- # if options.exclude_prizes:
- # cards = combine_cards(cards, 'Prize', 'prizes')
-
- # Group all the special cards together
- if options.special_card_groups:
- keep_cards = [] # holds the cards that are to be kept
- group_cards = {} # holds the cards for each group
- for card in cards:
- if not card.group_tag:
- keep_cards.append(card) # not part of a group, so just keep the card
- else:
- # have a card in a group
- if card.group_tag not in group_cards:
- # First card of a group
- group_cards[card.group_tag] = card # save to update cost later
- # this card becomes the card holder for the whole group.
- card.card_tag = card.group_tag
- # These text fields should be updated later if there is a translation for this group_tag.
- error_msg = "ERROR: Missing language entry for group_tab '%s'." % card.group_tag
- card.name = card.group_tag # For now, change the name to the group_tab
- card.description = error_msg
- card.extra = error_msg
- if card.isEvent():
- card.cost = "*"
- if card.isLandmark():
- card.cost = ""
- # now save the card
- keep_cards.append(card)
- else:
- # subsequent cards in the group. Update group info, but don't keep the card.
- if card.group_top:
- # this is a designated card to represent the group, so update important data
- group_cards[card.group_tag].cost = card.cost
- group_cards[card.group_tag].potcost = card.potcost
- group_cards[card.group_tag].debtcost = card.debtcost
- group_cards[card.group_tag].types = card.types
- group_cards[card.group_tag].image = card.image
-
- group_cards[card.group_tag].addCardCount(card.count) # increase the count
- # group_cards[card.group_tag].set_lowest_cost(card) # set holder to lowest cost of the two cards
-
- cards = keep_cards
-
- # Now fix up card costs
- for card in cards:
- if card.card_tag in group_cards:
- if group_cards[card.group_tag].isEvent():
- group_cards[card.group_tag].cost = "*"
- group_cards[card.group_tag].debtcost = 0
- group_cards[card.group_tag].potcost = 0
- if group_cards[card.group_tag].isLandmark():
- group_cards[card.group_tag].cost = ""
- group_cards[card.group_tag].debtcost = 0
- group_cards[card.group_tag].potcost = 0
-
- # Get the final type names in the requested language
- Card.type_names = add_type_text(options, Card.type_names, LANGUAGE_DEFAULT)
- if options.language != LANGUAGE_DEFAULT:
- Card.type_names = add_type_text(options, Card.type_names, options.language)
- for card in cards:
- card.types_name = ' - '.join([Card.type_names[t] for t in card.types]).upper()
-
- # Get the card bonus keywords in the requested language
- bonus = add_bonus_regex(options, LANGUAGE_DEFAULT)
- Card.addBonusRegex(bonus)
- if options.language != LANGUAGE_DEFAULT:
- bonus = add_bonus_regex(options, options.language)
- Card.addBonusRegex(bonus)
-
- # Fix up cardset text. Waited as long as possible.
- Card.sets = add_set_text(options, Card.sets, LANGUAGE_DEFAULT)
- if options.language != LANGUAGE_DEFAULT:
- Card.sets = add_set_text(options, Card.sets, options.language)
-
- for card in cards:
- if card.cardset_tag in Card.sets:
- if 'set_name' in Card.sets[card.cardset_tag].keys():
- card.cardset = Card.sets[card.cardset_tag]['set_name']
-
- # If expansion names given, then remove any cards not in those expansions
- # Expansion names can be the names from the language or the cardset_tag
- if options.expansions:
- options.expansions = set([e.lower() for e in options.expansions])
- wantedExpansions = set()
- knownExpansions = set()
- # Match sets that either start with the expansion set key (used by cardset_tag)
- # or the actual name of the set/expansion in the specified language.
- for e in options.expansions:
- for s in Card.sets:
- if (s.lower().startswith(e) or
- Card.sets[s].get('set_name', "").lower().startswith(e)):
- wantedExpansions.add(s)
- knownExpansions.add(e)
-
- # Give indication if an imput did not match anything
- unknownExpansions = options.expansions - knownExpansions
- if unknownExpansions:
- print "Error - unknown expansion(s): %s" % ", ".join(unknownExpansions)
-
- # Now keep only the cards that were in the expansions requested
- filteredCards = []
- for c in cards:
- if c.cardset_tag in wantedExpansions:
- filteredCards.append(c)
- cards = filteredCards
-
- # Now add text to the cards. Waited as long as possible to catch all groupings
- cards = add_card_text(options, cards, LANGUAGE_DEFAULT)
- if options.language != LANGUAGE_DEFAULT:
- cards = add_card_text(options, cards, options.language)
-
- # Get list of cards from a file
- if options.cardlist:
- cardlist = set()
- with open(options.cardlist) as cardfile:
- for line in cardfile:
- cardlist.add(line.strip())
- if cardlist:
- cards = [card for card in cards if card.name in cardlist]
-
- # Set up the card sorter
- cardSorter = CardSorter(
- options.order,
- [card.name for card in cards if card.cardset.lower() == 'base'])
- if options.base_cards_with_expansion:
- cards = [card for card in cards if card.cardset.lower() != 'base']
- else:
- cards = [card for card in cards
- if not cardSorter.isBaseExpansionCard(card)]
-
- # Add expansion divider
- if options.expansion_dividers:
-
- cardnamesByExpansion = {}
- for c in cards:
- if cardSorter.isBaseExpansionCard(c):
- continue
- cardnamesByExpansion.setdefault(c.cardset, []).append(c.name.strip().replace(' ', ' '))
-
- for set_tag, set_values in Card.sets.iteritems():
- exp = set_values["set_name"]
- if exp in cardnamesByExpansion:
- exp_name = exp
-
- count = len(cardnamesByExpansion[exp])
- if 'no_randomizer' in set_values:
- if set_values['no_randomizer']:
- count = 0
-
- if not options.expansion_dividers_long_name:
- if 'short_name' in set_values:
- exp_name = set_values['short_name']
-
- c = Card(name=exp_name,
- cardset=exp,
- cardset_tag=set_tag,
- types=("Expansion", ),
- cost=None,
- description=' | '.join(sorted(cardnamesByExpansion[exp])),
- count=count,
- card_tag=set_tag)
- cards.append(c)
-
- # Now sort what is left
- cards.sort(key=cardSorter)
-
- return cards
-
-
-def calculate_layout(options, cards=[]):
-
- dominionCardWidth, dominionCardHeight = parse_cardsize(options.size,
- options.sleeved)
- paperwidth, paperheight = parse_papersize(options.papersize)
-
- if options.orientation == "vertical":
- dividerWidth, dividerBaseHeight = dominionCardHeight, dominionCardWidth
- else:
- dividerWidth, dividerBaseHeight = dominionCardWidth, dominionCardHeight
-
- if options.tab_name_align == "center":
- options.tab_name_align = "centre"
-
- if options.tab_side == "full" and options.tab_name_align == "edge":
- # This case does not make sense since there are two tab edges in this case. So picking left edge.
- print >> sys.stderr, "** Warning: Aligning card name as 'left' for 'full' tabs **"
- options.tab_name_align = "left"
-
- fixedMargins = False
- if options.tabs_only:
- # fixed for Avery 8867 for now
- minmarginwidth = 0.86 * cm # was 0.76
- minmarginheight = 1.37 * cm # was 1.27
- labelHeight = 1.07 * cm # was 1.27
- labelWidth = 4.24 * cm # was 4.44
- horizontalBorderSpace = 0.96 * cm # was 0.76
- verticalBorderSpace = 0.20 * cm # was 0.01
- dividerBaseHeight = 0
- dividerWidth = labelWidth
- fixedMargins = True
- else:
- minmarginwidth, minmarginheight = parseDimensions(options.minmargin)
- if options.tab_side == "full":
- labelWidth = dividerWidth
- else:
- labelWidth = options.tabwidth * cm
- labelHeight = .9 * cm
- horizontalBorderSpace = options.horizontal_gap * cm
- verticalBorderSpace = options.vertical_gap * cm
-
- dividerHeight = dividerBaseHeight + labelHeight
-
- dividerWidthReserved = dividerWidth + horizontalBorderSpace
- dividerHeightReserved = dividerHeight + verticalBorderSpace
- if options.wrapper:
- max_card_stack_height = max(c.getStackHeight(options.thickness)
- for c in cards)
- dividerHeightReserved = (dividerHeightReserved * 2) + (
- max_card_stack_height * 2)
- print "Max Card Stack Height: {:.2f}cm ".format(max_card_stack_height)
-
- # Notch measurements
- notch_height = 0.25 * cm # thumb notch height
- notch_width1 = options.notch_length * cm # thumb notch width: top away from tab
- notch_width2 = 0.00 * cm # thumb notch width: bottom on side of tab
-
- add_opt(options, 'dividerWidth', dividerWidth)
- add_opt(options, 'dividerHeight', dividerHeight)
- add_opt(options, 'dividerBaseHeight', dividerBaseHeight)
- add_opt(options, 'dividerWidthReserved', dividerWidthReserved)
- add_opt(options, 'dividerHeightReserved', dividerHeightReserved)
- add_opt(options, 'labelWidth', labelWidth)
- add_opt(options, 'labelHeight', labelHeight)
- add_opt(options, 'notch_height', notch_height)
- add_opt(options, 'notch_width1', notch_width1)
- add_opt(options, 'notch_width2', notch_width2)
-
- # as we don't draw anything in the final border, it shouldn't count towards how many tabs we can fit
- # so it gets added back in to the page size here
- numDividersVerticalP = int(
- (paperheight - 2 * minmarginheight + verticalBorderSpace) /
- options.dividerHeightReserved)
- numDividersHorizontalP = int(
- (paperwidth - 2 * minmarginwidth + horizontalBorderSpace) /
- options.dividerWidthReserved)
- numDividersVerticalL = int(
- (paperwidth - 2 * minmarginwidth + verticalBorderSpace) /
- options.dividerHeightReserved)
- numDividersHorizontalL = int(
- (paperheight - 2 * minmarginheight + horizontalBorderSpace) /
- options.dividerWidthReserved)
-
- if ((numDividersVerticalL * numDividersHorizontalL > numDividersVerticalP *
- numDividersHorizontalP) and not fixedMargins):
- add_opt(options, 'numDividersVertical', numDividersVerticalL)
- add_opt(options, 'numDividersHorizontal', numDividersHorizontalL)
- add_opt(options, 'paperheight', paperwidth)
- add_opt(options, 'paperwidth', paperheight)
- add_opt(options, 'minHorizontalMargin', minmarginheight)
- add_opt(options, 'minVerticalMargin', minmarginwidth)
- else:
- add_opt(options, 'numDividersVertical', numDividersVerticalP)
- add_opt(options, 'numDividersHorizontal', numDividersHorizontalP)
- add_opt(options, 'paperheight', paperheight)
- add_opt(options, 'paperwidth', paperwidth)
- add_opt(options, 'minHorizontalMargin', minmarginheight)
- add_opt(options, 'minVerticalMargin', minmarginwidth)
-
- if not fixedMargins:
- # dynamically max margins
- add_opt(options, 'horizontalMargin',
- (options.paperwidth - options.numDividersHorizontal *
- options.dividerWidthReserved + horizontalBorderSpace) / 2)
- add_opt(options, 'verticalMargin',
- (options.paperheight - options.numDividersVertical *
- options.dividerHeightReserved + verticalBorderSpace) / 2)
- else:
- add_opt(options, 'horizontalMargin', minmarginwidth)
- add_opt(options, 'verticalMargin', minmarginheight)
-
-
-def generate(options, data_path):
-
- add_opt(options, 'data_path', data_path)
-
- cards = read_write_card_data(options)
- assert cards, "No cards after reading"
- cards = filter_sort_cards(cards, options)
- assert cards, "No cards after filtering/sorting"
-
- calculate_layout(options, cards)
-
- print "Paper dimensions: {:.2f}cm (w) x {:.2f}cm (h)".format(
- options.paperwidth / cm, options.paperheight / cm)
- print "Tab dimensions: {:.2f}cm (w) x {:.2f}cm (h)".format(
- options.dividerWidthReserved / cm, options.dividerHeightReserved / cm)
- print '{} dividers horizontally, {} vertically'.format(
- options.numDividersHorizontal, options.numDividersVertical)
- print "Margins: {:.2f}cm h, {:.2f}cm v\n".format(
- options.horizontalMargin / cm, options.verticalMargin / cm)
-
- dd = DividerDrawer()
- dd.draw(cards, options)
-
-
-def main(arglist, data_path):
- options = parse_opts(arglist)
- return generate(options, data_path)
+__version__ = '2.2'
diff --git a/card_db/cards_db.json b/domdiv/card_db/cards_db.json
similarity index 100%
rename from card_db/cards_db.json
rename to domdiv/card_db/cards_db.json
diff --git a/card_db/de/bonuses_de.json b/domdiv/card_db/de/bonuses_de.json
similarity index 100%
rename from card_db/de/bonuses_de.json
rename to domdiv/card_db/de/bonuses_de.json
diff --git a/card_db/de/cards_de.json b/domdiv/card_db/de/cards_de.json
similarity index 100%
rename from card_db/de/cards_de.json
rename to domdiv/card_db/de/cards_de.json
diff --git a/card_db/de/sets_de.json b/domdiv/card_db/de/sets_de.json
similarity index 100%
rename from card_db/de/sets_de.json
rename to domdiv/card_db/de/sets_de.json
diff --git a/card_db/de/types_de.json b/domdiv/card_db/de/types_de.json
similarity index 100%
rename from card_db/de/types_de.json
rename to domdiv/card_db/de/types_de.json
diff --git a/card_db/en_us/bonuses_en_us.json b/domdiv/card_db/en_us/bonuses_en_us.json
similarity index 100%
rename from card_db/en_us/bonuses_en_us.json
rename to domdiv/card_db/en_us/bonuses_en_us.json
diff --git a/card_db/en_us/cards_en_us.json b/domdiv/card_db/en_us/cards_en_us.json
similarity index 100%
rename from card_db/en_us/cards_en_us.json
rename to domdiv/card_db/en_us/cards_en_us.json
diff --git a/card_db/en_us/sets_en_us.json b/domdiv/card_db/en_us/sets_en_us.json
similarity index 100%
rename from card_db/en_us/sets_en_us.json
rename to domdiv/card_db/en_us/sets_en_us.json
diff --git a/card_db/en_us/types_en_us.json b/domdiv/card_db/en_us/types_en_us.json
similarity index 100%
rename from card_db/en_us/types_en_us.json
rename to domdiv/card_db/en_us/types_en_us.json
diff --git a/card_db/fr/bonuses_fr.json b/domdiv/card_db/fr/bonuses_fr.json
similarity index 100%
rename from card_db/fr/bonuses_fr.json
rename to domdiv/card_db/fr/bonuses_fr.json
diff --git a/card_db/fr/cards_fr.json b/domdiv/card_db/fr/cards_fr.json
similarity index 100%
rename from card_db/fr/cards_fr.json
rename to domdiv/card_db/fr/cards_fr.json
diff --git a/card_db/fr/sets_fr.json b/domdiv/card_db/fr/sets_fr.json
similarity index 100%
rename from card_db/fr/sets_fr.json
rename to domdiv/card_db/fr/sets_fr.json
diff --git a/card_db/fr/types_fr.json b/domdiv/card_db/fr/types_fr.json
similarity index 100%
rename from card_db/fr/types_fr.json
rename to domdiv/card_db/fr/types_fr.json
diff --git a/card_db/it/bonuses_it.json b/domdiv/card_db/it/bonuses_it.json
similarity index 100%
rename from card_db/it/bonuses_it.json
rename to domdiv/card_db/it/bonuses_it.json
diff --git a/card_db/it/cards_it.json b/domdiv/card_db/it/cards_it.json
similarity index 100%
rename from card_db/it/cards_it.json
rename to domdiv/card_db/it/cards_it.json
diff --git a/card_db/it/sets_it.json b/domdiv/card_db/it/sets_it.json
similarity index 100%
rename from card_db/it/sets_it.json
rename to domdiv/card_db/it/sets_it.json
diff --git a/card_db/it/types_it.json b/domdiv/card_db/it/types_it.json
similarity index 100%
rename from card_db/it/types_it.json
rename to domdiv/card_db/it/types_it.json
diff --git a/card_db/nl_du/bonuses_nl_du.json b/domdiv/card_db/nl_du/bonuses_nl_du.json
similarity index 100%
rename from card_db/nl_du/bonuses_nl_du.json
rename to domdiv/card_db/nl_du/bonuses_nl_du.json
diff --git a/card_db/nl_du/cards_nl_du.json b/domdiv/card_db/nl_du/cards_nl_du.json
similarity index 100%
rename from card_db/nl_du/cards_nl_du.json
rename to domdiv/card_db/nl_du/cards_nl_du.json
diff --git a/card_db/nl_du/sets_nl_du.json b/domdiv/card_db/nl_du/sets_nl_du.json
similarity index 100%
rename from card_db/nl_du/sets_nl_du.json
rename to domdiv/card_db/nl_du/sets_nl_du.json
diff --git a/card_db/nl_du/types_nl_du.json b/domdiv/card_db/nl_du/types_nl_du.json
similarity index 100%
rename from card_db/nl_du/types_nl_du.json
rename to domdiv/card_db/nl_du/types_nl_du.json
diff --git a/card_db/sets_db.json b/domdiv/card_db/sets_db.json
similarity index 100%
rename from card_db/sets_db.json
rename to domdiv/card_db/sets_db.json
diff --git a/card_db/translation.txt b/domdiv/card_db/translation.txt
similarity index 100%
rename from card_db/translation.txt
rename to domdiv/card_db/translation.txt
diff --git a/card_db/types_db.json b/domdiv/card_db/types_db.json
similarity index 100%
rename from card_db/types_db.json
rename to domdiv/card_db/types_db.json
diff --git a/card_db/xx/bonuses_xx.json b/domdiv/card_db/xx/bonuses_xx.json
similarity index 100%
rename from card_db/xx/bonuses_xx.json
rename to domdiv/card_db/xx/bonuses_xx.json
diff --git a/card_db/xx/cards_xx.json b/domdiv/card_db/xx/cards_xx.json
similarity index 100%
rename from card_db/xx/cards_xx.json
rename to domdiv/card_db/xx/cards_xx.json
diff --git a/card_db/xx/sets_xx.json b/domdiv/card_db/xx/sets_xx.json
similarity index 100%
rename from card_db/xx/sets_xx.json
rename to domdiv/card_db/xx/sets_xx.json
diff --git a/card_db/xx/translation.txt b/domdiv/card_db/xx/translation.txt
similarity index 100%
rename from card_db/xx/translation.txt
rename to domdiv/card_db/xx/translation.txt
diff --git a/card_db/xx/types_xx.json b/domdiv/card_db/xx/types_xx.json
similarity index 100%
rename from card_db/xx/types_xx.json
rename to domdiv/card_db/xx/types_xx.json
diff --git a/domdiv/draw.py b/domdiv/draw.py
index db753fa..696195f 100644
--- a/domdiv/draw.py
+++ b/domdiv/draw.py
@@ -2,6 +2,8 @@ import os
import re
import sys
+import pkg_resources
+
from reportlab.lib.units import cm
from reportlab.pdfbase import pdfmetrics
from reportlab.lib.styles import getSampleStyleSheet
@@ -25,25 +27,40 @@ class DividerDrawer(object):
self.odd = True
self.canvas = None
- def registerFonts(self):
- dirn = os.path.join(self.options.data_path, 'fonts')
- regularMpath = os.path.join(dirn, 'MinionPro-Regular.ttf')
- boldMpath = os.path.join(dirn, 'MinionPro-Bold.ttf')
- obliqueMpath = os.path.join(dirn, 'MinionPro-It.ttf')
+ @staticmethod
+ def get_image_filepath(fname):
+ return pkg_resources.resource_filename('domdiv', os.path.join('images', fname))
- if os.path.isfile(regularMpath) and os.path.isfile(boldMpath) and os.path.isfile(obliqueMpath):
- self.fontNameRegular = 'MinionPro-Regular'
- pdfmetrics.registerFont(TTFont(self.fontNameRegular, regularMpath))
- self.fontNameBold = 'MinionPro-Bold'
- pdfmetrics.registerFont(TTFont(self.fontNameBold, boldMpath))
- self.fontNameOblique = 'MinionPro-Oblique'
- pdfmetrics.registerFont(TTFont(self.fontNameOblique, obliqueMpath))
- else:
- print >> sys.stderr, "Warning, Minion Pro Font ttf file(s) not found! Falling back on Times. Tried:"
- print >> sys.stderr, regularMpath + ' ' + boldMpath + ' & ' + obliqueMpath
- self.fontNameRegular = 'Times-Roman'
- self.fontNameBold = 'Times-Bold'
- self.fontNameOblique = 'Times-Oblique'
+ def registerFonts(self):
+ # the following are filenames from both an Adobe Reader install and a download from fontsgeek
+ fontfilenames = ['MinionPro-Regular.ttf',
+ 'MinionPro-Bold.ttf',
+ 'MinionPro-It.ttf',
+ 'Minion Pro Regular.ttf',
+ 'Minion Pro Bold.ttf',
+ 'Minion Pro Italic.ttf']
+ # first figure out which, if any, are present
+ fontpaths = [os.path.join('fonts', fname) for fname in fontfilenames]
+ fontpaths = [fpath for fpath in fontpaths if pkg_resources.resource_exists('domdiv', fpath)]
+ self.font_mapping = {'Regular': [fpath for fpath in fontpaths if 'Regular' in fpath],
+ 'Bold': [fpath for fpath in fontpaths if 'Bold' in fpath],
+ 'Italic': [fpath for fpath in fontpaths if 'It' in fpath]}
+ # then make sure that we have at least one for each type
+ for fonttype in self.font_mapping:
+ if not len(self.font_mapping[fonttype]):
+ print >> sys.stderr, ("Warning, Minion Pro ttf file for {} missing from domdiv/fonts!",
+ " Falling back on Times font for everything.").format(fonttype)
+ self.font_mapping = {'Regular': 'Times-Roman',
+ 'Bold': 'Times-Bold',
+ 'Italic': 'Times-Oblique'}
+ break
+ else:
+ # and finally register and tag one for each type
+ ftag = 'MinionPro-{}'.format(fonttype)
+ pdfmetrics.registerFont(TTFont(ftag,
+ pkg_resources.resource_filename('domdiv',
+ self.font_mapping[fonttype][0])))
+ self.font_mapping[fonttype] = ftag
def wantCentreTab(self, card):
return (card.isExpansion() and self.options.centre_expansion_dividers) or self.options.tab_side == "centre"
@@ -209,45 +226,44 @@ class DividerDrawer(object):
def add_inline_images(self, text, fontsize):
# Coins
- path = os.path.join(self.options.data_path, 'images')
- replace = '
'
- replace = replace % (path, fontsize * 2.4)
+ replace = '
'
+ replace = replace.format(DividerDrawer.get_image_filepath('coin_small_1.png'), fontsize * 2.4)
text = re.sub('(\d+)\s*\<\*COIN\*\>', replace, text)
- replace = '
'
- replace = replace % (path, fontsize * 1.2)
+ replace = '
'
+ replace = replace.format(DividerDrawer.get_image_filepath('coin_small_1.png'), fontsize * 1.2)
text = re.sub('(\d+)\s(c|C)oin(s)?', replace, text)
- replace = '
'
- replace = replace % (path, fontsize * 1.2)
+ replace = '
'
+ replace = replace.format(DividerDrawer.get_image_filepath('coin_small_question.png'), fontsize * 1.2)
text = re.sub('\?\s(c|C)oin(s)?', replace, text)
- replace = '
'
- replace = replace % (path, fontsize * 1.2)
+ replace = '
'
+ replace = replace.format(DividerDrawer.get_image_filepath('coin_small_empty.png'), fontsize * 1.2)
text = re.sub('empty\s(c|C)oin(s)?', replace, text)
text = re.sub('\_\s(c|C)oin(s)?', replace, text)
# VP
- replace = '
'
- replace = replace % (path, fontsize * 1.5)
+ replace = '
'
+ replace = replace.format(DividerDrawer.get_image_filepath('victory_emblem.png'), fontsize * 1.5)
text = re.sub('(?:\s+|\<)VP(?:\s+|\>|\.|$)', replace, text)
- replace = '\\1 '
- replace += '
'
- replace = replace % (fontsize * 1.5, path, fontsize * 2.5)
+ replace = '\\1 '
+ replace += '
'
+ replace = replace.format(fontsize * 1.5, DividerDrawer.get_image_filepath('victory_emblem.png'), fontsize * 2.5)
text = re.sub('(\d+)\s*\<\*VP\*\>', replace, text)
# Debt
- replace = '
'
- replace = replace % (path, fontsize * 1.2)
+ replace = '
'
+ replace = replace.format(DividerDrawer.get_image_filepath('debt_1.png'), fontsize * 1.2)
text = re.sub('(\d+)\sDebt', replace, text)
- replace = '
'
- replace = replace % (path, fontsize * 1.2)
+ replace = '
'
+ replace = replace.format(DividerDrawer.get_image_filepath('debt.png'), fontsize * 1.2)
text = re.sub('Debt', replace, text)
# Potion
- replace = '\\1 '
- replace += '
'
- replace = replace % (fontsize * 1.5, path, fontsize * 2.0)
+ replace = '\\1 '
+ replace += '
'
+ replace = replace.format(fontsize * 1.5, DividerDrawer.get_image_filepath('potion_small.png'), fontsize * 2.0)
text = re.sub('(\d+)\s*\<\*POTION\*\>', replace, text)
- replace = '
'
- replace = replace % (path, fontsize * 1.2)
+ replace = '
'
+ replace = replace.format(DividerDrawer.get_image_filepath('potion_small.png'), fontsize * 1.2)
text = re.sub('Potion', replace, text)
return text.strip()
@@ -373,24 +389,24 @@ class DividerDrawer(object):
width += 16
x -= 16
self.canvas.drawImage(
- os.path.join(self.options.data_path, 'images', 'card.png'),
+ DividerDrawer.get_image_filepath('card.png'),
x,
countHeight,
16,
16,
preserveAspectRatio=True,
mask='auto')
- self.canvas.setFont(self.fontNameBold, 10)
+ self.canvas.setFont(self.font_mapping['Bold'], 10)
self.canvas.drawCentredString(x + 8, countHeight + 4, str(value))
# now draw the number of sets
if count > 1:
count_string = u"{}\u00d7".format(count)
- width_string = stringWidth(count_string, self.fontNameRegular, 10)
+ width_string = stringWidth(count_string, self.font_mapping['Regular'], 10)
width_string -= 1 # adjust to make it closer to image
width += width_string
x -= width_string
- self.canvas.setFont(self.fontNameRegular, 10)
+ self.canvas.setFont(self.font_mapping['Regular'], 10)
self.canvas.drawString(x, countHeight + 4, count_string)
return width + 1
@@ -409,14 +425,14 @@ class DividerDrawer(object):
(card.potcost and int(card.cost) == 0))):
self.canvas.drawImage(
- os.path.join(self.options.data_path, 'images', 'coin_small.png'),
+ DividerDrawer.get_image_filepath('coin_small.png'),
x,
coinHeight,
16,
16,
preserveAspectRatio=True,
mask='auto')
- self.canvas.setFont(self.fontNameBold, 12)
+ self.canvas.setFont(self.font_mapping['Bold'], 12)
self.canvas.drawCentredString(x + 8, costHeight, str(card.cost))
self.canvas.setFillColorRGB(0, 0, 0)
x += 17
@@ -424,7 +440,7 @@ class DividerDrawer(object):
if card.debtcost:
self.canvas.drawImage(
- os.path.join(self.options.data_path, 'images', 'debt.png'),
+ DividerDrawer.get_image_filepath('debt.png'),
x,
coinHeight,
16,
@@ -432,7 +448,7 @@ class DividerDrawer(object):
preserveAspectRatio=True,
mask=[170, 255, 170, 255, 170, 255])
self.canvas.setFillColorRGB(1, 1, 1)
- self.canvas.setFont(self.fontNameBold, 12)
+ self.canvas.setFont(self.font_mapping['Bold'], 12)
self.canvas.drawCentredString(x + 8, costHeight, str(card.debtcost))
self.canvas.setFillColorRGB(0, 0, 0)
x += 17
@@ -440,7 +456,7 @@ class DividerDrawer(object):
if card.potcost:
self.canvas.drawImage(
- os.path.join(self.options.data_path, 'images', 'potion.png'),
+ DividerDrawer.get_image_filepath('potion.png'),
x,
potHeight,
potSize,
@@ -455,7 +471,7 @@ class DividerDrawer(object):
# set image
w = 2
self.canvas.drawImage(
- os.path.join(self.options.data_path, 'images', setImage),
+ DividerDrawer.get_image_filepath(setImage),
x,
y,
14,
@@ -468,11 +484,11 @@ class DividerDrawer(object):
name_parts = name.split()
for i, part in enumerate(name_parts):
if i != 0:
- w += pdfmetrics.stringWidth(' ', self.fontNameRegular,
+ w += pdfmetrics.stringWidth(' ', self.font_mapping['Regular'],
fontSize)
- w += pdfmetrics.stringWidth(part[0], self.fontNameRegular,
+ w += pdfmetrics.stringWidth(part[0], self.font_mapping['Regular'],
fontSize)
- w += pdfmetrics.stringWidth(part[1:], self.fontNameRegular,
+ w += pdfmetrics.stringWidth(part[1:], self.font_mapping['Regular'],
fontSize - 2)
return w
@@ -519,7 +535,7 @@ class DividerDrawer(object):
img = card.getType().getNoCoinTabImageFile()
if not self.options.no_tab_artwork and img:
self.canvas.drawImage(
- os.path.join(self.options.data_path, 'images', img),
+ DividerDrawer.get_image_filepath(img),
1,
0,
self.options.labelWidth - 2,
@@ -548,7 +564,7 @@ class DividerDrawer(object):
if self.options.use_text_set_icon:
setImageHeight = card.getType().getTabTextHeightOffset()
setText = card.setTextIcon()
- self.canvas.setFont(self.fontNameOblique, 8)
+ self.canvas.setFont(self.font_mapping['Italic'], 8)
if setText is None:
setText = ""
@@ -611,10 +627,10 @@ class DividerDrawer(object):
w = textInset
def drawWordPiece(text, fontSize):
- self.canvas.setFont(self.fontNameRegular, fontSize)
+ self.canvas.setFont(self.font_mapping['Regular'], fontSize)
if text != ' ':
self.canvas.drawString(w, h, text)
- return pdfmetrics.stringWidth(text, self.fontNameRegular,
+ return pdfmetrics.stringWidth(text, self.font_mapping['Regular'],
fontSize)
for i, word in enumerate(words):
@@ -638,10 +654,10 @@ class DividerDrawer(object):
words.reverse()
def drawWordPiece(text, fontSize):
- self.canvas.setFont(self.fontNameRegular, fontSize)
+ self.canvas.setFont(self.font_mapping['Regular'], fontSize)
if text != ' ':
self.canvas.drawRightString(w, h, text)
- return -pdfmetrics.stringWidth(text, self.fontNameRegular,
+ return -pdfmetrics.stringWidth(text, self.font_mapping['Regular'],
fontSize)
for i, word in enumerate(words):
@@ -655,7 +671,7 @@ class DividerDrawer(object):
self.canvas.translate(0, -card.getStackHeight(
self.options.thickness)) # move into area used by the wrapper
fontSize = 8 # use the smallest font
- self.canvas.setFont(self.fontNameRegular, fontSize)
+ self.canvas.setFont(self.font_mapping['Regular'], fontSize)
textHeight = fontSize - 2
textHeight = card.getStackHeight(
@@ -666,10 +682,10 @@ class DividerDrawer(object):
fontSize) / 2
def drawWordPiece(text, fontSize):
- self.canvas.setFont(self.fontNameRegular, fontSize)
+ self.canvas.setFont(self.font_mapping['Regular'], fontSize)
if text != ' ':
self.canvas.drawString(w, h, text)
- return pdfmetrics.stringWidth(text, self.fontNameRegular,
+ return pdfmetrics.stringWidth(text, self.font_mapping['Regular'],
fontSize)
for i, word in enumerate(words):
@@ -737,7 +753,7 @@ class DividerDrawer(object):
# use all the available space, even if it is not centered on the card
fontSize = 8
failover = False
- width = stringWidth(card.types_name, self.fontNameRegular, fontSize)
+ width = stringWidth(card.types_name, self.font_mapping['Regular'], fontSize)
while width > textWidth:
fontSize -= .01
if fontSize < 6 and not failover:
@@ -746,11 +762,11 @@ class DividerDrawer(object):
w = left_margin + (textWidth2 / 2)
fontSize = 8
failover = True
- width = stringWidth(card.types_name, self.fontNameRegular, fontSize)
+ width = stringWidth(card.types_name, self.font_mapping['Regular'], fontSize)
# Print out the text in the right spot
h = totalHeight - usedHeight - 0.5 * cm
- self.canvas.setFont(self.fontNameRegular, fontSize)
+ self.canvas.setFont(self.font_mapping['Regular'], fontSize)
if card.types_name != ' ':
self.canvas.drawCentredString(w, h, card.types_name)
drewTopIcon = True
@@ -873,7 +889,7 @@ class DividerDrawer(object):
# calculate the text height, font size, and orientation
maxFontsize = 12
minFontsize = 6
- fontname = self.fontNameRegular
+ fontname = self.font_mapping['Regular']
font = pdfmetrics.getFont(fontname)
fontHeightRelative = (
font.face.ascent + abs(font.face.descent)) / 1000.0
diff --git a/domdiv/fonts/README.md b/domdiv/fonts/README.md
new file mode 100644
index 0000000..e4b53f2
--- /dev/null
+++ b/domdiv/fonts/README.md
@@ -0,0 +1,4 @@
+#### Fonts
+I believe I cannot distribute one font (Minion Pro) domdiv uses as they are commercially sold by Adobe. However, the font files are included with every install of the free Adobe Reader. For example, on Windows 7 they are in C:\Program Files (x86)\Adobe\Reader 9.0\Resource\Font called `MinionPro-Regular.otf`, `MinionPro-Bold.otf` and `MinionPro-It.otf`.
+
+Sadly, these fonts use features of the otf format that are not support by the reportlab package. Thus, they need to first be converted to ttf (TrueType) format. I used the open source package fontforge to do the conversion. Included as 'convert.ff' is a script for fontforge to do the conversion, on Mac OS X with fontforge installed through macports you can just run `./convert.ff MinionPro-Regular.otf`, `./convert.ff MinionPro-Bold.otf` and `./convert.ff MinionPro-It.otf`. With other fontforge installations, you'll need to change the first line of convert.ff to point to your fontforge executable. I have not done this step under Windows - I imagine it may be possible with a cygwin install of fontforge or some such method. Copy these converted files to this subdirectory.
diff --git a/images/action-shelter.png b/domdiv/images/action-shelter.png
similarity index 100%
rename from images/action-shelter.png
rename to domdiv/images/action-shelter.png
diff --git a/images/action-shelter_nc.png b/domdiv/images/action-shelter_nc.png
similarity index 100%
rename from images/action-shelter_nc.png
rename to domdiv/images/action-shelter_nc.png
diff --git a/images/action-treasure_nc.png b/domdiv/images/action-treasure_nc.png
similarity index 100%
rename from images/action-treasure_nc.png
rename to domdiv/images/action-treasure_nc.png
diff --git a/images/action-victory.png b/domdiv/images/action-victory.png
similarity index 100%
rename from images/action-victory.png
rename to domdiv/images/action-victory.png
diff --git a/images/action-victory_nc.png b/domdiv/images/action-victory_nc.png
similarity index 100%
rename from images/action-victory_nc.png
rename to domdiv/images/action-victory_nc.png
diff --git a/images/action.png b/domdiv/images/action.png
similarity index 100%
rename from images/action.png
rename to domdiv/images/action.png
diff --git a/images/action_nc.png b/domdiv/images/action_nc.png
similarity index 100%
rename from images/action_nc.png
rename to domdiv/images/action_nc.png
diff --git a/images/adventures_set.png b/domdiv/images/adventures_set.png
similarity index 100%
rename from images/adventures_set.png
rename to domdiv/images/adventures_set.png
diff --git a/images/alchemy_set.png b/domdiv/images/alchemy_set.png
similarity index 100%
rename from images/alchemy_set.png
rename to domdiv/images/alchemy_set.png
diff --git a/images/black_market_set.png b/domdiv/images/black_market_set.png
similarity index 100%
rename from images/black_market_set.png
rename to domdiv/images/black_market_set.png
diff --git a/images/card.png b/domdiv/images/card.png
similarity index 100%
rename from images/card.png
rename to domdiv/images/card.png
diff --git a/images/coin.png b/domdiv/images/coin.png
similarity index 100%
rename from images/coin.png
rename to domdiv/images/coin.png
diff --git a/images/coin_small.png b/domdiv/images/coin_small.png
similarity index 100%
rename from images/coin_small.png
rename to domdiv/images/coin_small.png
diff --git a/images/coin_small_0.png b/domdiv/images/coin_small_0.png
similarity index 100%
rename from images/coin_small_0.png
rename to domdiv/images/coin_small_0.png
diff --git a/images/coin_small_1.png b/domdiv/images/coin_small_1.png
similarity index 100%
rename from images/coin_small_1.png
rename to domdiv/images/coin_small_1.png
diff --git a/images/coin_small_10.png b/domdiv/images/coin_small_10.png
similarity index 100%
rename from images/coin_small_10.png
rename to domdiv/images/coin_small_10.png
diff --git a/images/coin_small_11.png b/domdiv/images/coin_small_11.png
similarity index 100%
rename from images/coin_small_11.png
rename to domdiv/images/coin_small_11.png
diff --git a/images/coin_small_12.png b/domdiv/images/coin_small_12.png
similarity index 100%
rename from images/coin_small_12.png
rename to domdiv/images/coin_small_12.png
diff --git a/images/coin_small_13.png b/domdiv/images/coin_small_13.png
similarity index 100%
rename from images/coin_small_13.png
rename to domdiv/images/coin_small_13.png
diff --git a/images/coin_small_2.png b/domdiv/images/coin_small_2.png
similarity index 100%
rename from images/coin_small_2.png
rename to domdiv/images/coin_small_2.png
diff --git a/images/coin_small_3.png b/domdiv/images/coin_small_3.png
similarity index 100%
rename from images/coin_small_3.png
rename to domdiv/images/coin_small_3.png
diff --git a/images/coin_small_4.png b/domdiv/images/coin_small_4.png
similarity index 100%
rename from images/coin_small_4.png
rename to domdiv/images/coin_small_4.png
diff --git a/images/coin_small_5.png b/domdiv/images/coin_small_5.png
similarity index 100%
rename from images/coin_small_5.png
rename to domdiv/images/coin_small_5.png
diff --git a/images/coin_small_6.png b/domdiv/images/coin_small_6.png
similarity index 100%
rename from images/coin_small_6.png
rename to domdiv/images/coin_small_6.png
diff --git a/images/coin_small_7.png b/domdiv/images/coin_small_7.png
similarity index 100%
rename from images/coin_small_7.png
rename to domdiv/images/coin_small_7.png
diff --git a/images/coin_small_8.png b/domdiv/images/coin_small_8.png
similarity index 100%
rename from images/coin_small_8.png
rename to domdiv/images/coin_small_8.png
diff --git a/images/coin_small_9.png b/domdiv/images/coin_small_9.png
similarity index 100%
rename from images/coin_small_9.png
rename to domdiv/images/coin_small_9.png
diff --git a/images/coin_small_empty.png b/domdiv/images/coin_small_empty.png
similarity index 100%
rename from images/coin_small_empty.png
rename to domdiv/images/coin_small_empty.png
diff --git a/images/coin_small_question.png b/domdiv/images/coin_small_question.png
similarity index 100%
rename from images/coin_small_question.png
rename to domdiv/images/coin_small_question.png
diff --git a/images/cornucopia_set.png b/domdiv/images/cornucopia_set.png
similarity index 100%
rename from images/cornucopia_set.png
rename to domdiv/images/cornucopia_set.png
diff --git a/images/curse.png b/domdiv/images/curse.png
similarity index 100%
rename from images/curse.png
rename to domdiv/images/curse.png
diff --git a/images/curse_nc.png b/domdiv/images/curse_nc.png
similarity index 100%
rename from images/curse_nc.png
rename to domdiv/images/curse_nc.png
diff --git a/images/dark_ages_set.png b/domdiv/images/dark_ages_set.png
similarity index 100%
rename from images/dark_ages_set.png
rename to domdiv/images/dark_ages_set.png
diff --git a/images/debt.png b/domdiv/images/debt.png
similarity index 100%
rename from images/debt.png
rename to domdiv/images/debt.png
diff --git a/images/debt_1.png b/domdiv/images/debt_1.png
similarity index 100%
rename from images/debt_1.png
rename to domdiv/images/debt_1.png
diff --git a/images/debt_2.png b/domdiv/images/debt_2.png
similarity index 100%
rename from images/debt_2.png
rename to domdiv/images/debt_2.png
diff --git a/images/debt_40.png b/domdiv/images/debt_40.png
similarity index 100%
rename from images/debt_40.png
rename to domdiv/images/debt_40.png
diff --git a/images/debt_5.png b/domdiv/images/debt_5.png
similarity index 100%
rename from images/debt_5.png
rename to domdiv/images/debt_5.png
diff --git a/images/debt_6.png b/domdiv/images/debt_6.png
similarity index 100%
rename from images/debt_6.png
rename to domdiv/images/debt_6.png
diff --git a/images/debt_8.png b/domdiv/images/debt_8.png
similarity index 100%
rename from images/debt_8.png
rename to domdiv/images/debt_8.png
diff --git a/images/dominion1stEdition_set.png b/domdiv/images/dominion1stEdition_set.png
similarity index 100%
rename from images/dominion1stEdition_set.png
rename to domdiv/images/dominion1stEdition_set.png
diff --git a/images/dominion2ndEdition_set.png b/domdiv/images/dominion2ndEdition_set.png
similarity index 100%
rename from images/dominion2ndEdition_set.png
rename to domdiv/images/dominion2ndEdition_set.png
diff --git a/images/duration-reaction_nc.png b/domdiv/images/duration-reaction_nc.png
similarity index 100%
rename from images/duration-reaction_nc.png
rename to domdiv/images/duration-reaction_nc.png
diff --git a/images/duration.png b/domdiv/images/duration.png
similarity index 100%
rename from images/duration.png
rename to domdiv/images/duration.png
diff --git a/images/duration_nc.png b/domdiv/images/duration_nc.png
similarity index 100%
rename from images/duration_nc.png
rename to domdiv/images/duration_nc.png
diff --git a/images/empires_set.png b/domdiv/images/empires_set.png
similarity index 100%
rename from images/empires_set.png
rename to domdiv/images/empires_set.png
diff --git a/images/envoy_set.png b/domdiv/images/envoy_set.png
similarity index 100%
rename from images/envoy_set.png
rename to domdiv/images/envoy_set.png
diff --git a/images/event_nc.png b/domdiv/images/event_nc.png
similarity index 100%
rename from images/event_nc.png
rename to domdiv/images/event_nc.png
diff --git a/images/expansion_nc.png b/domdiv/images/expansion_nc.png
similarity index 100%
rename from images/expansion_nc.png
rename to domdiv/images/expansion_nc.png
diff --git a/images/governor_set.png b/domdiv/images/governor_set.png
similarity index 100%
rename from images/governor_set.png
rename to domdiv/images/governor_set.png
diff --git a/images/guilds_set.png b/domdiv/images/guilds_set.png
similarity index 100%
rename from images/guilds_set.png
rename to domdiv/images/guilds_set.png
diff --git a/images/hinterlands_set.png b/domdiv/images/hinterlands_set.png
similarity index 100%
rename from images/hinterlands_set.png
rename to domdiv/images/hinterlands_set.png
diff --git a/images/intrigue1stEdition_set.png b/domdiv/images/intrigue1stEdition_set.png
similarity index 100%
rename from images/intrigue1stEdition_set.png
rename to domdiv/images/intrigue1stEdition_set.png
diff --git a/images/intrigue2ndEdition_set.png b/domdiv/images/intrigue2ndEdition_set.png
similarity index 100%
rename from images/intrigue2ndEdition_set.png
rename to domdiv/images/intrigue2ndEdition_set.png
diff --git a/images/landmark_nc.png b/domdiv/images/landmark_nc.png
similarity index 100%
rename from images/landmark_nc.png
rename to domdiv/images/landmark_nc.png
diff --git a/images/potion.png b/domdiv/images/potion.png
similarity index 100%
rename from images/potion.png
rename to domdiv/images/potion.png
diff --git a/images/potion_small.png b/domdiv/images/potion_small.png
similarity index 100%
rename from images/potion_small.png
rename to domdiv/images/potion_small.png
diff --git a/images/prince_set.png b/domdiv/images/prince_set.png
similarity index 100%
rename from images/prince_set.png
rename to domdiv/images/prince_set.png
diff --git a/images/promo_set.png b/domdiv/images/promo_set.png
similarity index 100%
rename from images/promo_set.png
rename to domdiv/images/promo_set.png
diff --git a/images/prosperity_set.png b/domdiv/images/prosperity_set.png
similarity index 100%
rename from images/prosperity_set.png
rename to domdiv/images/prosperity_set.png
diff --git a/images/reaction-shelter.png b/domdiv/images/reaction-shelter.png
similarity index 100%
rename from images/reaction-shelter.png
rename to domdiv/images/reaction-shelter.png
diff --git a/images/reaction-shelter_nc.png b/domdiv/images/reaction-shelter_nc.png
similarity index 100%
rename from images/reaction-shelter_nc.png
rename to domdiv/images/reaction-shelter_nc.png
diff --git a/images/reaction.png b/domdiv/images/reaction.png
similarity index 100%
rename from images/reaction.png
rename to domdiv/images/reaction.png
diff --git a/images/reaction_nc.png b/domdiv/images/reaction_nc.png
similarity index 100%
rename from images/reaction_nc.png
rename to domdiv/images/reaction_nc.png
diff --git a/images/reserve-treasure_nc.png b/domdiv/images/reserve-treasure_nc.png
similarity index 100%
rename from images/reserve-treasure_nc.png
rename to domdiv/images/reserve-treasure_nc.png
diff --git a/images/reserve-victory_nc.png b/domdiv/images/reserve-victory_nc.png
similarity index 100%
rename from images/reserve-victory_nc.png
rename to domdiv/images/reserve-victory_nc.png
diff --git a/images/reserve_nc.png b/domdiv/images/reserve_nc.png
similarity index 100%
rename from images/reserve_nc.png
rename to domdiv/images/reserve_nc.png
diff --git a/images/ruins.png b/domdiv/images/ruins.png
similarity index 100%
rename from images/ruins.png
rename to domdiv/images/ruins.png
diff --git a/images/ruins_nc.png b/domdiv/images/ruins_nc.png
similarity index 100%
rename from images/ruins_nc.png
rename to domdiv/images/ruins_nc.png
diff --git a/images/seaside_set.png b/domdiv/images/seaside_set.png
similarity index 100%
rename from images/seaside_set.png
rename to domdiv/images/seaside_set.png
diff --git a/images/shelter.png b/domdiv/images/shelter.png
similarity index 100%
rename from images/shelter.png
rename to domdiv/images/shelter.png
diff --git a/images/shelter_nc.png b/domdiv/images/shelter_nc.png
similarity index 100%
rename from images/shelter_nc.png
rename to domdiv/images/shelter_nc.png
diff --git a/images/stash_set.png b/domdiv/images/stash_set.png
similarity index 100%
rename from images/stash_set.png
rename to domdiv/images/stash_set.png
diff --git a/images/treasure-reaction.png b/domdiv/images/treasure-reaction.png
similarity index 100%
rename from images/treasure-reaction.png
rename to domdiv/images/treasure-reaction.png
diff --git a/images/treasure-reaction_nc.png b/domdiv/images/treasure-reaction_nc.png
similarity index 100%
rename from images/treasure-reaction_nc.png
rename to domdiv/images/treasure-reaction_nc.png
diff --git a/images/treasure-victory.png b/domdiv/images/treasure-victory.png
similarity index 100%
rename from images/treasure-victory.png
rename to domdiv/images/treasure-victory.png
diff --git a/images/treasure-victory_nc.png b/domdiv/images/treasure-victory_nc.png
similarity index 100%
rename from images/treasure-victory_nc.png
rename to domdiv/images/treasure-victory_nc.png
diff --git a/images/treasure.png b/domdiv/images/treasure.png
similarity index 100%
rename from images/treasure.png
rename to domdiv/images/treasure.png
diff --git a/images/treasure_nc.png b/domdiv/images/treasure_nc.png
similarity index 100%
rename from images/treasure_nc.png
rename to domdiv/images/treasure_nc.png
diff --git a/images/victory-reaction.png b/domdiv/images/victory-reaction.png
similarity index 100%
rename from images/victory-reaction.png
rename to domdiv/images/victory-reaction.png
diff --git a/images/victory-reaction_nc.png b/domdiv/images/victory-reaction_nc.png
similarity index 100%
rename from images/victory-reaction_nc.png
rename to domdiv/images/victory-reaction_nc.png
diff --git a/images/victory-shelter.png b/domdiv/images/victory-shelter.png
similarity index 100%
rename from images/victory-shelter.png
rename to domdiv/images/victory-shelter.png
diff --git a/images/victory-shelter_nc.png b/domdiv/images/victory-shelter_nc.png
similarity index 100%
rename from images/victory-shelter_nc.png
rename to domdiv/images/victory-shelter_nc.png
diff --git a/images/victory.png b/domdiv/images/victory.png
similarity index 100%
rename from images/victory.png
rename to domdiv/images/victory.png
diff --git a/images/victory_emblem.png b/domdiv/images/victory_emblem.png
similarity index 100%
rename from images/victory_emblem.png
rename to domdiv/images/victory_emblem.png
diff --git a/images/victory_nc.png b/domdiv/images/victory_nc.png
similarity index 100%
rename from images/victory_nc.png
rename to domdiv/images/victory_nc.png
diff --git a/images/walled_village_set.png b/domdiv/images/walled_village_set.png
similarity index 100%
rename from images/walled_village_set.png
rename to domdiv/images/walled_village_set.png
diff --git a/domdiv/main.py b/domdiv/main.py
new file mode 100644
index 0000000..23c03df
--- /dev/null
+++ b/domdiv/main.py
@@ -0,0 +1,1036 @@
+import os
+import codecs
+import json
+import sys
+import argparse
+import copy
+
+import pkg_resources
+
+import reportlab.lib.pagesizes as pagesizes
+from reportlab.lib.units import cm
+
+from cards import Card
+from cards import CardType
+from draw import DividerDrawer
+
+LOCATION_CHOICES = ["tab", "body-top", "hide"]
+NAME_ALIGN_CHOICES = ["left", "right", "centre", "edge"]
+TAB_SIDE_CHOICES = ["left", "right", "left-alternate", "right-alternate",
+ "centre", "full"]
+TEXT_CHOICES = ["card", "rules", "blank"]
+EDITION_CHOICES = ["1", "2", "latest", "all"]
+
+EXPANSION_CHOICES = ["adventures", "alchemy", "cornucopia", "dark ages",
+ "dominion1stEdition", "dominion2ndEdition", "dominion2ndEditionUpgrade",
+ "empires", "guilds", "hinterlands",
+ "intrigue1stEdition", "intrigue2ndEdition", "intrigue2ndEditionUpgrade",
+ "promo", "prosperity", "seaside"]
+
+LANGUAGE_DEFAULT = 'en_us' # the primary language used if a language's parts are missing
+LANGUAGE_XX = 'xx' # a dummy language for starting translations
+
+
+def get_languages(path):
+ languages = []
+ for name in pkg_resources.resource_listdir('domdiv', path):
+ dir_path = os.path.join(path, name)
+ if pkg_resources.resource_isdir('domdiv', dir_path):
+ cards_file = os.path.join(dir_path, "cards_{}.json".format(name))
+ sets_file = os.path.join(dir_path, "sets_{}.json".format(name))
+ types_file = os.path.join(dir_path, "types_{}.json".format(name))
+ if (pkg_resources.resource_exists('domdiv', cards_file) and
+ pkg_resources.resource_exists('domdiv', sets_file) and
+ pkg_resources.resource_exists('domdiv', types_file)):
+ languages.append(name)
+ if LANGUAGE_XX in languages:
+ languages.remove(LANGUAGE_XX)
+ return languages
+
+
+LANGUAGE_CHOICES = get_languages("card_db")
+
+
+def add_opt(options, option, value):
+ assert not hasattr(options, option)
+ setattr(options, option, value)
+
+
+def parse_opts(cmdline_args=None):
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+ description="Generate Dominion Dividers",
+ epilog="Source can be found at 'https://github.com/sumpfork/dominiontabs'. "
+ "An online version can be found at 'http://domtabs.sandflea.org/'. ")
+
+ # Basic Divider Information
+ group_basic = parser.add_argument_group(
+ 'Basic Divider Options',
+ 'Basic choices for the dividers.')
+ group_basic.add_argument(
+ '--outfile', '-o',
+ dest="outfile",
+ default="dominion_dividers.pdf",
+ help="The output file name.")
+ group_basic.add_argument(
+ "--papersize",
+ dest="papersize",
+ default=None,
+ help="The size of paper to use; '<%%f>x<%%f>' (size in cm), or 'A4', or 'LETTER'. "
+ "If not specified, it will default to system defaults, and if the system defaults "
+ "are not found, then to 'LETTER'.")
+ group_basic.add_argument(
+ "--language", "-l",
+ dest="language",
+ default=LANGUAGE_DEFAULT,
+ choices=LANGUAGE_CHOICES,
+ help="Language of divider text.")
+ group_basic.add_argument(
+ "--orientation",
+ choices=["horizontal", "vertical"],
+ dest="orientation",
+ default="horizontal",
+ help="Either horizontal or vertical divider orientation.")
+ group_basic.add_argument(
+ "--size",
+ dest="size",
+ default='normal',
+ help="Dimentions of the cards to use with the dividers '<%%f>x<%%f>' (size in cm), "
+ "or 'normal' = '9.1x5.9', or 'sleeved' = '9.4x6.15'.")
+ group_basic.add_argument(
+ "--sleeved",
+ action="store_true",
+ dest="sleeved",
+ help="Same as --size=sleeved.")
+ group_basic.add_argument(
+ "--order",
+ choices=["expansion", "global", "colour", "cost"],
+ default="expansion",
+ dest="order",
+ help="Sort order for the dividers: "
+ " 'global' will sort by card name;"
+ " 'expansion' will sort by expansion, then card name;"
+ " 'colour' will sort by card type, then card name;"
+ " 'cost' will sort by expansion, then card cost, then name.")
+
+ # Divider Body
+ group_body = parser.add_argument_group(
+ 'Divider Body',
+ 'Changes what is displayed on the body of the dividers.')
+ group_body.add_argument(
+ "--front",
+ choices=TEXT_CHOICES,
+ dest="text_front",
+ default="card",
+ help="Text to print on the front of the divider; "
+ "'card' will print the text from the game card; "
+ "'rules' will print additional rules for the game card; "
+ "'blank' will not print text on the divider.")
+ group_body.add_argument(
+ "--back",
+ choices=TEXT_CHOICES + ["none"],
+ dest="text_back",
+ default="rules",
+ help="Text to print on the back of the divider; "
+ "'card' will print the text from the game card; "
+ "'rules' will print additional rules for the game card; "
+ "'blank' will not print text on the divider; "
+ "'none' will prevent the back pages from printing. ")
+ group_body.add_argument(
+ "--count",
+ action="store_true",
+ dest="count",
+ help="Display card count on body of the divider.")
+ group_body.add_argument(
+ "--types",
+ action="store_true",
+ dest="types",
+ help="Display card type on the body of the divider.")
+
+ # Divider Tab
+ group_tab = parser.add_argument_group(
+ 'Divider Tab',
+ 'Changes what is displayed on on the Divider Tab.')
+ group_tab.add_argument(
+ "--tab_side",
+ choices=TAB_SIDE_CHOICES,
+ dest="tab_side",
+ default="right-alternate",
+ help="Alignment of tab; "
+ "'left'/'right' forces all tabs to left/right side; "
+ "'left-alternate' will start on the left and then toggle between left and right for the tabs; "
+ "'right-alternate' will start on the right and then toggle between right and left for the tabs; "
+ "'centre' will force all label tabs to the centre; "
+ "'full' will force all label tabs to be full width of the divider.")
+ group_tab.add_argument(
+ "--tab_name_align",
+ choices=NAME_ALIGN_CHOICES + ["center"],
+ dest="tab_name_align",
+ default="left",
+ help="Alignment of text on the tab; "
+ "The 'edge' option will align the card name to the outside edge of the "
+ "tab, so that when using tabs on alternating sides, "
+ "the name is less likely to be hidden by the tab in front "
+ "(edge will revert to left when tab_side is full since there is no edge in that case).")
+ group_tab.add_argument(
+ "--tabwidth",
+ type=float,
+ default=4.0,
+ help="Width in cm of stick-up tab (ignored if --tab_side is 'full' or --tabs_only is used).")
+ group_tab.add_argument(
+ "--cost",
+ action="append",
+ choices=LOCATION_CHOICES,
+ default=['tab'],
+ help="Where to display the card cost; may be set to "
+ "'hide' to indicate it should not be displayed, or "
+ "given multiple times to show it in multiple places.")
+ group_tab.add_argument(
+ "--set_icon",
+ action="append",
+ choices=LOCATION_CHOICES,
+ default=['tab'],
+ help="Where to display the set icon; may be set to "
+ "'hide' to indicate it should not be displayed, or "
+ "given multiple times to show it in multiple places.")
+ group_tab.add_argument(
+ "--no-tab-artwork",
+ action="store_true",
+ dest="no_tab_artwork",
+ help="Don't show background artwork on tabs.")
+ group_tab.add_argument(
+ "--use-text-set-icon",
+ action="store_true",
+ dest="use_text_set_icon",
+ help="Use text/letters to represent a card's set instead of the set icon.")
+
+ # Expanion Dividers
+ group_expansion = parser.add_argument_group(
+ 'Expansion Dividers',
+ 'Adding separator dividers for each expansion.')
+ group_expansion.add_argument(
+ "--expansion_dividers",
+ action="store_true",
+ dest="expansion_dividers",
+ help="Add dividers describing each expansion set. "
+ "A list of cards in the expansion will be shown on the front of the divider.")
+ group_expansion.add_argument(
+ "--centre_expansion_dividers",
+ action="store_true",
+ dest="centre_expansion_dividers",
+ help='Centre the tabs on expansion dividers.')
+ group_expansion.add_argument(
+ "--expansion_dividers_long_name",
+ action="store_true",
+ dest="expansion_dividers_long_name",
+ help="Use the long name with edition information on the expansion divider tab. "
+ "Without this, the shorter expansion name is used on the expansion divider tab.")
+
+ # Divider Selection
+ group_select = parser.add_argument_group(
+ 'Divider Selection',
+ 'What expansions are used, and grouping of dividers.')
+ group_select.add_argument(
+ "--expansions", "--expansion",
+ nargs="*",
+ action="append",
+ dest="expansions",
+ help="Limit dividers to only the specified expansions. "
+ "If no limits are set, then all expansions are included. "
+ "Expansion names can also be given in the language specified by "
+ "the --language parameter. Any expansion with a space in the name must "
+ "be enclosed in quotes. This may be called multiple times. "
+ "Values are not case sensitive and can also match the starting characters "
+ "of an expansion name. For example, 'dominion' will match all expansions "
+ "that start with that name; Choices available in all languages include: %s" %
+ ", ".join("%s" % x for x in EXPANSION_CHOICES))
+ group_select.add_argument(
+ "--edition",
+ choices=EDITION_CHOICES,
+ dest="edition",
+ default="all",
+ help="Editions to include: "
+ "'1' is for all 1st Editions; "
+ "'2' is for all 2nd Editions; "
+ "'latest' is for the latest edition for each expansion; "
+ "'all' is for all editions of expansions; "
+ " This can be combined with other options to refine the expansions to include in the output.")
+ group_select.add_argument(
+ "--upgrade_with_expansion",
+ action="store_true",
+ dest="upgrade_with_expansion",
+ help="Include any new edition upgrade cards with the expansion being upgraded.")
+ group_select.add_argument(
+ "--base_cards_with_expansion",
+ action="store_true",
+ help="Print the base cards as part of the expansion (i.e., a divider for 'Silver' "
+ "will be printed as both a 'Dominion' card and as an 'Intrigue 1st Edition' card). "
+ "If this option is not given, all base cards are placed in their own 'Base' expansion.")
+ group_select.add_argument(
+ "--special_card_groups",
+ action="store_true",
+ help="Group cards that generally are used together "
+ "(e.g., Shelters, Tournament and Prizes, Urchin/Mercenary, etc.).")
+ group_select.add_argument(
+ "--include_blanks",
+ action="store_true",
+ help="Include a few dividers with extra text.")
+ group_select.add_argument(
+ "--exclude_events",
+ action="store_true",
+ help="Group all 'Event' cards across all expansions into one divider.")
+ group_select.add_argument(
+ "--exclude_landmarks",
+ action="store_true",
+ help="Group all 'Landmark' cards across all expansions into one divider.")
+
+ # Divider Sleeves/Wrappers
+ group_wrapper = parser.add_argument_group(
+ 'Card Sleeves/Wrappers',
+ 'Generating dividers that are card sleeves/wrappers.')
+ group_wrapper.add_argument(
+ "--wrapper",
+ action="store_true",
+ dest="wrapper",
+ help="Draw sleeves (aka wrapper) for the cards instead of a divider for the cards.")
+ group_wrapper.add_argument(
+ "--thickness",
+ type=float,
+ default=2.0,
+ help="Thickness of a stack of 60 cards (Copper) in centimeters. "
+ "Typically unsleeved cards are 2.0, thin sleeved cards are 2.4, and thick sleeved cards are 3.2. "
+ "This is only valid with the --wrapper option.")
+ group_wrapper.add_argument(
+ "--sleeved_thick",
+ action="store_true",
+ dest="sleeved_thick",
+ help="Same as --size=sleeved --thickness 3.2.")
+ group_wrapper.add_argument(
+ "--sleeved_thin",
+ action="store_true",
+ dest="sleeved_thin",
+ help="Same as --size=sleeved --thickness 2.4.")
+ group_wrapper.add_argument(
+ "--notch_length",
+ type=float,
+ default=0.0,
+ help="Length of thumb notch on wrapper in centimeters "
+ "(a value of 0.0 means no notch on wrapper). "
+ "This can make it easier to remove the actual cards from the wrapper. "
+ "This is only valid with the --wrapper option.")
+ group_wrapper.add_argument(
+ "--notch",
+ action="store_true",
+ dest="notch",
+ help="Same as --notch_length thickness 1.5.")
+
+ # Printing
+ group_printing = parser.add_argument_group(
+ 'Printing',
+ 'Changes how the Dividers are printed.')
+ group_printing.add_argument(
+ "--minmargin",
+ dest="minmargin",
+ default="1x1",
+ help="Page margin in cm in the form '<%%f>x<%%f>', left/right x top/bottom).")
+ group_printing.add_argument(
+ "--cropmarks",
+ action="store_true",
+ dest="cropmarks",
+ help="Print crop marks on both sides, rather than tab outlines on the front side.")
+ group_printing.add_argument(
+ "--linewidth",
+ type=float,
+ default=0.1,
+ help="Width of lines for card outlines and crop marks.")
+ group_printing.add_argument(
+ "--back_offset",
+ type=float,
+ dest="back_offset",
+ default=0,
+ help="Back page horizontal offset points to shift to the right. Only needed for some printers.")
+ group_printing.add_argument(
+ "--back_offset_height",
+ type=float,
+ dest="back_offset_height",
+ default=0,
+ help="Back page vertical offset points to shift upward. Only needed for some printers.")
+ group_printing.add_argument(
+ "--vertical_gap",
+ type=float,
+ default=0.0,
+ help="Vertical gap between dividers in centimeters.")
+ group_printing.add_argument(
+ "--horizontal_gap",
+ type=float,
+ default=0.0,
+ help="Horizontal gap between dividers in centimeters.")
+ group_printing.add_argument(
+ "--no-page-footer",
+ action="store_true",
+ dest="no_page_footer",
+ help="Do not print the expansion name at the bottom of the page.")
+ group_printing.add_argument(
+ "--num_pages",
+ type=int,
+ default=-1,
+ help="Stop generating dividers after this many pages, -1 for all.")
+ group_printing.add_argument(
+ "--tabs-only",
+ action="store_true",
+ dest="tabs_only",
+ help="Draw only the divider tabs and no divider outlines. "
+ "Used to print the divider tabs on labels.")
+
+ # Special processing
+ group_special = parser.add_argument_group(
+ 'Miscellaneous',
+ 'These options are generally not used.')
+ group_special.add_argument(
+ "--cardlist",
+ dest="cardlist",
+ help="Path to file that enumerates each card to be printed on its own line.")
+ group_special.add_argument(
+ "--write_json",
+ action="store_true",
+ dest="write_json",
+ help="Write json version of card definitions and extras.")
+
+ options = parser.parse_args(args=cmdline_args)
+
+ if options.sleeved_thick:
+ options.thickness = 3.2
+ options.sleeved = True
+
+ if options.sleeved_thin:
+ options.thickness = 2.4
+ options.sleeved = True
+
+ if options.notch:
+ options.notch_length = 1.5
+
+ if options.expansions:
+ # options.expansions is a list of lists. Reduce to single list
+ options.expansions = [item for sublist in options.expansions for item in sublist]
+
+ return options
+
+
+def parseDimensions(dimensionsStr):
+ x, y = dimensionsStr.upper().split('X', 1)
+ return (float(x) * cm, float(y) * cm)
+
+
+def generate_sample(options):
+ import cStringIO
+ from wand.image import Image
+ buf = cStringIO.StringIO()
+ options.num_pages = 1
+ generate(options, '.', buf)
+ with Image(blob=buf.getvalue()) as sample:
+ sample.format = 'png'
+ sample.save(filename='sample.png')
+
+
+def parse_papersize(spec):
+ papersize = None
+ if not spec:
+ if os.path.exists("/etc/papersize"):
+ papersize = open("/etc/papersize").readline().upper()
+ else:
+ papersize = 'LETTER'
+ else:
+ papersize = spec.upper()
+
+ try:
+ paperwidth, paperheight = getattr(pagesizes, papersize)
+ except AttributeError:
+ try:
+ paperwidth, paperheight = parseDimensions(papersize)
+ print 'Using custom paper size, %.2fcm x %.2fcm' % (
+ paperwidth / cm, paperheight / cm)
+ except ValueError:
+ paperwidth, paperheight = pagesizes.LETTER
+ return paperwidth, paperheight
+
+
+def parse_cardsize(spec, sleeved):
+ spec = spec.upper()
+ if spec == 'SLEEVED' or sleeved:
+ dominionCardWidth, dominionCardHeight = (9.4 * cm, 6.15 * cm)
+ print 'Using sleeved card size, %.2fcm x %.2fcm' % (
+ dominionCardWidth / cm, dominionCardHeight / cm)
+ elif spec in ['NORMAL', 'UNSLEEVED']:
+ dominionCardWidth, dominionCardHeight = (9.1 * cm, 5.9 * cm)
+ print 'Using normal card size, %.2fcm x%.2fcm' % (
+ dominionCardWidth / cm, dominionCardHeight / cm)
+ else:
+ dominionCardWidth, dominionCardHeight = parseDimensions(spec)
+ print 'Using custom card size, %.2fcm x %.2fcm' % (
+ dominionCardWidth / cm, dominionCardHeight / cm)
+ return dominionCardWidth, dominionCardHeight
+
+
+def get_resource_stream(path):
+ return codecs.EncodedFile(pkg_resources.resource_stream('domdiv', path), "utf-8")
+
+
+def read_card_data(options):
+
+ # Read in the card types
+ types_db_filepath = os.path.join("card_db", "types_db.json")
+ with get_resource_stream(types_db_filepath) as typefile:
+ Card.types = json.load(typefile, object_hook=CardType.decode_json)
+ assert Card.types, "Could not load any card types from database"
+
+ # extract unique types
+ type_list = []
+ for c in Card.types:
+ type_list = list(set(c.getTypeNames()) | set(type_list))
+ # set up the basic type translation. The actual language will be added later.
+ Card.type_names = {}
+ for t in type_list:
+ Card.type_names[t] = t
+
+ # turn Card.types into a dictionary for later
+ Card.types = dict(((c.getTypeNames(), c) for c in Card.types))
+
+ # Read in the card database
+ card_db_filepath = os.path.join("card_db", "cards_db.json")
+ with get_resource_stream(card_db_filepath) as cardfile:
+ cards = json.load(cardfile, object_hook=Card.decode_json)
+ assert cards, "Could not load any cards from database"
+
+ set_db_filepath = os.path.join("card_db", "sets_db.json")
+ with get_resource_stream(set_db_filepath) as setfile:
+ Card.sets = json.load(setfile)
+ assert Card.sets, "Could not load any sets from database"
+ for s in Card.sets:
+ if 'no_randomizer' not in Card.sets[s]:
+ Card.sets[s]['no_randomizer'] = False
+
+ # Set cardset_tag and expand cards that are used in multiple sets
+ new_cards = []
+ for card in cards:
+ sets = list(card.cardset_tags)
+ if len(sets) > 0:
+ # Set and save the first one
+ card.cardset_tag = sets.pop(0)
+ new_cards.append(card)
+ for s in sets:
+ # for the rest, create a copy of the first
+ if s:
+ new_card = copy.deepcopy(card)
+ new_card.cardset_tag = s
+ new_cards.append(new_card)
+ cards = new_cards
+
+ # Make sure each card has the right image file.
+ for card in cards:
+ card.image = card.setImage()
+
+ return cards
+
+
+class CardSorter(object):
+ def __init__(self, order, baseCards):
+ self.order = order
+ if order == "global":
+ self.sort_key = self.by_global_sort_key
+ elif order == "colour":
+ self.sort_key = self.by_colour_sort_key
+ elif order == "cost":
+ self.sort_key = self.by_cost_sort_key
+ else:
+ self.sort_key = self.by_expansion_sort_key
+
+ self.baseCards = baseCards
+
+ # When sorting cards, want to always put "base" cards after all
+ # kingdom cards, and order the base cards in a set order - the
+ # order they are listed in the database (ie, all normal treasures
+ # by worth, then potion, then all normal VP cards by worth, then
+ # trash)
+ def baseIndex(self, name):
+ try:
+ return self.baseCards.index(name)
+ except Exception:
+ return -1
+
+ def isBaseExpansionCard(self, card):
+ return card.cardset.lower() != 'base' and card.name in self.baseCards
+
+ def by_global_sort_key(self, card):
+ return int(card.isExpansion()), self.baseIndex(card.name), card.name
+
+ def by_expansion_sort_key(self, card):
+ return card.cardset, int(card.isExpansion()), self.baseIndex(
+ card.name), card.name
+
+ def by_colour_sort_key(self, card):
+ return card.getType().getTypeNames(), card.name
+
+ def by_cost_sort_key(self, card):
+ return card.cardset, int(card.isExpansion()), card.get_total_cost(card), card.name
+
+ def __call__(self, card):
+ return self.sort_key(card)
+
+
+def add_card_text(options, cards, language='en_us'):
+ language = language.lower()
+ # Read in the card text file
+ card_text_filepath = os.path.join("card_db",
+ language,
+ "cards_" + language.lower() + ".json")
+ with get_resource_stream(card_text_filepath) as card_text_file:
+ card_text = json.load(card_text_file)
+ assert language, "Could not load card text for %r" % language
+
+ # Now apply to all the cards
+ for card in cards:
+ if card.card_tag in card_text:
+ if 'name' in card_text[card.card_tag].keys():
+ card.name = card_text[card.card_tag]['name']
+ if 'description' in card_text[card.card_tag].keys():
+ card.description = card_text[card.card_tag]['description']
+ if 'extra' in card_text[card.card_tag].keys():
+ card.extra = card_text[card.card_tag]['extra']
+ return cards
+
+
+def add_set_text(options, sets, language='en_us'):
+ language = language.lower()
+ # Read in the set text and store for later
+ set_text_filepath = os.path.join("card_db",
+ language,
+ "sets_{}.json".format(language))
+ with get_resource_stream(set_text_filepath) as set_text_file:
+ set_text = json.load(set_text_file)
+ assert set_text, "Could not load set text for %r" % language
+
+ # Now apply to all the sets
+ for s in sets:
+ if s in set_text:
+ for key in set_text[s]:
+ sets[s][key] = set_text[s][key]
+ return sets
+
+
+def add_type_text(options, types={}, language='en_us'):
+ language = language.lower()
+ # Read in the type text and store for later
+ type_text_filepath = os.path.join("card_db",
+ language,
+ "types_{}.json".format(language))
+ with get_resource_stream(type_text_filepath) as type_text_file:
+ type_text = json.load(type_text_file)
+ assert type_text, "Could not load type text for %r" % language
+
+ # Now apply to all the types
+ used = {}
+ for type in types:
+ if type in type_text:
+ types[type] = type_text[type]
+ used[type] = True
+
+ for type in type_text:
+ if type not in used:
+ types[type] = type_text[type]
+
+ return types
+
+
+def add_bonus_regex(options, language='en_us'):
+ language = language.lower()
+ # Read in the bonus regex terms
+ bonus_regex_filepath = os.path.join("card_db",
+ language,
+ "bonuses_{}.json".format(language))
+ with get_resource_stream(bonus_regex_filepath) as bonus_regex_file:
+ bonus_regex = json.load(bonus_regex_file)
+ assert bonus_regex, "Could not load bonus keywords for %r" % language
+
+ if not bonus_regex:
+ bonus_regex = {}
+
+ return bonus_regex
+
+
+def combine_cards(cards, old_card_type, new_card_tag, new_cardset_tag, new_type):
+
+ holder = Card(name='*Replace Later*',
+ card_tag=new_card_tag,
+ group_tag=new_card_tag,
+ cardset_tag=new_cardset_tag,
+ types=(new_type, ),
+ count=0)
+ holder.image = holder.setImage()
+
+ filteredCards = []
+ for c in cards:
+ if c.isType(old_card_type):
+ holder.addCardCount(c.count) # keep track of count and skip card
+ else:
+ filteredCards.append(c) # Not the right type, keep card
+
+ if holder.getCardCount() > 0:
+ filteredCards.append(holder)
+
+ return filteredCards
+
+
+def filter_sort_cards(cards, options):
+
+ # Filter out cards by edition
+ if options.edition and options.edition != "all":
+ keep_sets = []
+ for set_tag in Card.sets:
+ for edition in Card.sets[set_tag]["edition"]:
+ if options.edition == edition:
+ keep_sets.append(set_tag)
+
+ keep_cards = [] # holds the cards that are to be kept
+ for card in cards:
+ if card.cardset_tag in keep_sets:
+ keep_cards.append(card)
+
+ cards = keep_cards
+
+ # Combine upgrade cards with their expansion
+ if options.upgrade_with_expansion:
+ for card in cards:
+ if card.cardset_tag == 'dominion2ndEditionUpgrade':
+ card.cardset_tag = 'dominion1stEdition'
+ elif card.cardset_tag == 'intrigue2ndEditionUpgrade':
+ card.cardset_tag = 'intrigue1stEdition'
+
+ # Combine all Events across all expansions
+ if options.exclude_events:
+ cards = combine_cards(cards,
+ old_card_type="Event",
+ new_type="Events",
+ new_card_tag='events',
+ new_cardset_tag='extras'
+ )
+ if options.expansions:
+ options.expansions.append("extras")
+
+ # Combine all Landmarks across all expansions
+ if options.exclude_landmarks:
+ cards = combine_cards(cards,
+ old_card_type="Landmark",
+ new_type="Landmarks",
+ new_card_tag='landmarks',
+ new_cardset_tag='extras'
+ )
+ if options.expansions:
+ options.expansions.append("extras")
+
+ # FIX THIS: Combine all Prizes across all expansions
+ # if options.exclude_prizes:
+ # cards = combine_cards(cards, 'Prize', 'prizes')
+
+ # Group all the special cards together
+ if options.special_card_groups:
+ keep_cards = [] # holds the cards that are to be kept
+ group_cards = {} # holds the cards for each group
+ for card in cards:
+ if not card.group_tag:
+ keep_cards.append(card) # not part of a group, so just keep the card
+ else:
+ # have a card in a group
+ if card.group_tag not in group_cards:
+ # First card of a group
+ group_cards[card.group_tag] = card # save to update cost later
+ # this card becomes the card holder for the whole group.
+ card.card_tag = card.group_tag
+ # These text fields should be updated later if there is a translation for this group_tag.
+ error_msg = "ERROR: Missing language entry for group_tab '%s'." % card.group_tag
+ card.name = card.group_tag # For now, change the name to the group_tab
+ card.description = error_msg
+ card.extra = error_msg
+ if card.isEvent():
+ card.cost = "*"
+ if card.isLandmark():
+ card.cost = ""
+ # now save the card
+ keep_cards.append(card)
+ else:
+ # subsequent cards in the group. Update group info, but don't keep the card.
+ if card.group_top:
+ # this is a designated card to represent the group, so update important data
+ group_cards[card.group_tag].cost = card.cost
+ group_cards[card.group_tag].potcost = card.potcost
+ group_cards[card.group_tag].debtcost = card.debtcost
+ group_cards[card.group_tag].types = card.types
+ group_cards[card.group_tag].image = card.image
+
+ group_cards[card.group_tag].addCardCount(card.count) # increase the count
+ # group_cards[card.group_tag].set_lowest_cost(card) # set holder to lowest cost of the two cards
+
+ cards = keep_cards
+
+ # Now fix up card costs
+ for card in cards:
+ if card.card_tag in group_cards:
+ if group_cards[card.group_tag].isEvent():
+ group_cards[card.group_tag].cost = "*"
+ group_cards[card.group_tag].debtcost = 0
+ group_cards[card.group_tag].potcost = 0
+ if group_cards[card.group_tag].isLandmark():
+ group_cards[card.group_tag].cost = ""
+ group_cards[card.group_tag].debtcost = 0
+ group_cards[card.group_tag].potcost = 0
+
+ # Get the final type names in the requested language
+ Card.type_names = add_type_text(options, Card.type_names, LANGUAGE_DEFAULT)
+ if options.language != LANGUAGE_DEFAULT:
+ Card.type_names = add_type_text(options, Card.type_names, options.language)
+ for card in cards:
+ card.types_name = ' - '.join([Card.type_names[t] for t in card.types]).upper()
+
+ # Get the card bonus keywords in the requested language
+ bonus = add_bonus_regex(options, LANGUAGE_DEFAULT)
+ Card.addBonusRegex(bonus)
+ if options.language != LANGUAGE_DEFAULT:
+ bonus = add_bonus_regex(options, options.language)
+ Card.addBonusRegex(bonus)
+
+ # Fix up cardset text. Waited as long as possible.
+ Card.sets = add_set_text(options, Card.sets, LANGUAGE_DEFAULT)
+ if options.language != LANGUAGE_DEFAULT:
+ Card.sets = add_set_text(options, Card.sets, options.language)
+
+ for card in cards:
+ if card.cardset_tag in Card.sets:
+ if 'set_name' in Card.sets[card.cardset_tag].keys():
+ card.cardset = Card.sets[card.cardset_tag]['set_name']
+
+ # If expansion names given, then remove any cards not in those expansions
+ # Expansion names can be the names from the language or the cardset_tag
+ if options.expansions:
+ options.expansions = set([e.lower() for e in options.expansions])
+ wantedExpansions = set()
+ knownExpansions = set()
+ # Match sets that either start with the expansion set key (used by cardset_tag)
+ # or the actual name of the set/expansion in the specified language.
+ for e in options.expansions:
+ for s in Card.sets:
+ if (s.lower().startswith(e) or
+ Card.sets[s].get('set_name', "").lower().startswith(e)):
+ wantedExpansions.add(s)
+ knownExpansions.add(e)
+
+ # Give indication if an imput did not match anything
+ unknownExpansions = options.expansions - knownExpansions
+ if unknownExpansions:
+ print "Error - unknown expansion(s): %s" % ", ".join(unknownExpansions)
+
+ # Now keep only the cards that were in the expansions requested
+ filteredCards = []
+ for c in cards:
+ if c.cardset_tag in wantedExpansions:
+ filteredCards.append(c)
+ cards = filteredCards
+
+ # Now add text to the cards. Waited as long as possible to catch all groupings
+ cards = add_card_text(options, cards, LANGUAGE_DEFAULT)
+ if options.language != LANGUAGE_DEFAULT:
+ cards = add_card_text(options, cards, options.language)
+
+ # Get list of cards from a file
+ if options.cardlist:
+ cardlist = set()
+ with open(options.cardlist) as cardfile:
+ for line in cardfile:
+ cardlist.add(line.strip())
+ if cardlist:
+ cards = [card for card in cards if card.name in cardlist]
+
+ # Set up the card sorter
+ cardSorter = CardSorter(
+ options.order,
+ [card.name for card in cards if card.cardset.lower() == 'base'])
+ if options.base_cards_with_expansion:
+ cards = [card for card in cards if card.cardset.lower() != 'base']
+ else:
+ cards = [card for card in cards
+ if not cardSorter.isBaseExpansionCard(card)]
+
+ # Add expansion divider
+ if options.expansion_dividers:
+
+ cardnamesByExpansion = {}
+ for c in cards:
+ if cardSorter.isBaseExpansionCard(c):
+ continue
+ cardnamesByExpansion.setdefault(c.cardset, []).append(c.name.strip().replace(' ', ' '))
+
+ for set_tag, set_values in Card.sets.iteritems():
+ exp = set_values["set_name"]
+ if exp in cardnamesByExpansion:
+ exp_name = exp
+
+ count = len(cardnamesByExpansion[exp])
+ if 'no_randomizer' in set_values:
+ if set_values['no_randomizer']:
+ count = 0
+
+ if not options.expansion_dividers_long_name:
+ if 'short_name' in set_values:
+ exp_name = set_values['short_name']
+
+ c = Card(name=exp_name,
+ cardset=exp,
+ cardset_tag=set_tag,
+ types=("Expansion", ),
+ cost=None,
+ description=' | '.join(sorted(cardnamesByExpansion[exp])),
+ count=count,
+ card_tag=set_tag)
+ cards.append(c)
+
+ # Now sort what is left
+ cards.sort(key=cardSorter)
+
+ return cards
+
+
+def calculate_layout(options, cards=[]):
+
+ dominionCardWidth, dominionCardHeight = parse_cardsize(options.size,
+ options.sleeved)
+ paperwidth, paperheight = parse_papersize(options.papersize)
+
+ if options.orientation == "vertical":
+ dividerWidth, dividerBaseHeight = dominionCardHeight, dominionCardWidth
+ else:
+ dividerWidth, dividerBaseHeight = dominionCardWidth, dominionCardHeight
+
+ if options.tab_name_align == "center":
+ options.tab_name_align = "centre"
+
+ if options.tab_side == "full" and options.tab_name_align == "edge":
+ # This case does not make sense since there are two tab edges in this case. So picking left edge.
+ print >> sys.stderr, "** Warning: Aligning card name as 'left' for 'full' tabs **"
+ options.tab_name_align = "left"
+
+ fixedMargins = False
+ if options.tabs_only:
+ # fixed for Avery 8867 for now
+ minmarginwidth = 0.86 * cm # was 0.76
+ minmarginheight = 1.37 * cm # was 1.27
+ labelHeight = 1.07 * cm # was 1.27
+ labelWidth = 4.24 * cm # was 4.44
+ horizontalBorderSpace = 0.96 * cm # was 0.76
+ verticalBorderSpace = 0.20 * cm # was 0.01
+ dividerBaseHeight = 0
+ dividerWidth = labelWidth
+ fixedMargins = True
+ else:
+ minmarginwidth, minmarginheight = parseDimensions(options.minmargin)
+ if options.tab_side == "full":
+ labelWidth = dividerWidth
+ else:
+ labelWidth = options.tabwidth * cm
+ labelHeight = .9 * cm
+ horizontalBorderSpace = options.horizontal_gap * cm
+ verticalBorderSpace = options.vertical_gap * cm
+
+ dividerHeight = dividerBaseHeight + labelHeight
+
+ dividerWidthReserved = dividerWidth + horizontalBorderSpace
+ dividerHeightReserved = dividerHeight + verticalBorderSpace
+ if options.wrapper:
+ max_card_stack_height = max(c.getStackHeight(options.thickness)
+ for c in cards)
+ dividerHeightReserved = (dividerHeightReserved * 2) + (
+ max_card_stack_height * 2)
+ print "Max Card Stack Height: {:.2f}cm ".format(max_card_stack_height)
+
+ # Notch measurements
+ notch_height = 0.25 * cm # thumb notch height
+ notch_width1 = options.notch_length * cm # thumb notch width: top away from tab
+ notch_width2 = 0.00 * cm # thumb notch width: bottom on side of tab
+
+ add_opt(options, 'dividerWidth', dividerWidth)
+ add_opt(options, 'dividerHeight', dividerHeight)
+ add_opt(options, 'dividerBaseHeight', dividerBaseHeight)
+ add_opt(options, 'dividerWidthReserved', dividerWidthReserved)
+ add_opt(options, 'dividerHeightReserved', dividerHeightReserved)
+ add_opt(options, 'labelWidth', labelWidth)
+ add_opt(options, 'labelHeight', labelHeight)
+ add_opt(options, 'notch_height', notch_height)
+ add_opt(options, 'notch_width1', notch_width1)
+ add_opt(options, 'notch_width2', notch_width2)
+
+ # as we don't draw anything in the final border, it shouldn't count towards how many tabs we can fit
+ # so it gets added back in to the page size here
+ numDividersVerticalP = int(
+ (paperheight - 2 * minmarginheight + verticalBorderSpace) /
+ options.dividerHeightReserved)
+ numDividersHorizontalP = int(
+ (paperwidth - 2 * minmarginwidth + horizontalBorderSpace) /
+ options.dividerWidthReserved)
+ numDividersVerticalL = int(
+ (paperwidth - 2 * minmarginwidth + verticalBorderSpace) /
+ options.dividerHeightReserved)
+ numDividersHorizontalL = int(
+ (paperheight - 2 * minmarginheight + horizontalBorderSpace) /
+ options.dividerWidthReserved)
+
+ if ((numDividersVerticalL * numDividersHorizontalL > numDividersVerticalP *
+ numDividersHorizontalP) and not fixedMargins):
+ add_opt(options, 'numDividersVertical', numDividersVerticalL)
+ add_opt(options, 'numDividersHorizontal', numDividersHorizontalL)
+ add_opt(options, 'paperheight', paperwidth)
+ add_opt(options, 'paperwidth', paperheight)
+ add_opt(options, 'minHorizontalMargin', minmarginheight)
+ add_opt(options, 'minVerticalMargin', minmarginwidth)
+ else:
+ add_opt(options, 'numDividersVertical', numDividersVerticalP)
+ add_opt(options, 'numDividersHorizontal', numDividersHorizontalP)
+ add_opt(options, 'paperheight', paperheight)
+ add_opt(options, 'paperwidth', paperwidth)
+ add_opt(options, 'minHorizontalMargin', minmarginheight)
+ add_opt(options, 'minVerticalMargin', minmarginwidth)
+
+ if not fixedMargins:
+ # dynamically max margins
+ add_opt(options, 'horizontalMargin',
+ (options.paperwidth - options.numDividersHorizontal *
+ options.dividerWidthReserved + horizontalBorderSpace) / 2)
+ add_opt(options, 'verticalMargin',
+ (options.paperheight - options.numDividersVertical *
+ options.dividerHeightReserved + verticalBorderSpace) / 2)
+ else:
+ add_opt(options, 'horizontalMargin', minmarginwidth)
+ add_opt(options, 'verticalMargin', minmarginheight)
+
+
+def generate(options):
+
+ cards = read_card_data(options)
+ assert cards, "No cards after reading"
+ cards = filter_sort_cards(cards, options)
+ assert cards, "No cards after filtering/sorting"
+
+ calculate_layout(options, cards)
+
+ print "Paper dimensions: {:.2f}cm (w) x {:.2f}cm (h)".format(
+ options.paperwidth / cm, options.paperheight / cm)
+ print "Tab dimensions: {:.2f}cm (w) x {:.2f}cm (h)".format(
+ options.dividerWidthReserved / cm, options.dividerHeightReserved / cm)
+ print '{} dividers horizontally, {} vertically'.format(
+ options.numDividersHorizontal, options.numDividersVertical)
+ print "Margins: {:.2f}cm h, {:.2f}cm v\n".format(
+ options.horizontalMargin / cm, options.verticalMargin / cm)
+
+ dd = DividerDrawer()
+ dd.draw(cards, options)
+
+
+def main():
+ options = parse_opts()
+ return generate(options)
diff --git a/tests/__init__.py b/domdiv/tests/__init__.py
similarity index 100%
rename from tests/__init__.py
rename to domdiv/tests/__init__.py
diff --git a/tests/carddb_tests.py b/domdiv/tests/carddb_tests.py
similarity index 67%
rename from tests/carddb_tests.py
rename to domdiv/tests/carddb_tests.py
index 0be126c..6d3f234 100644
--- a/tests/carddb_tests.py
+++ b/domdiv/tests/carddb_tests.py
@@ -1,16 +1,15 @@
import unittest
-from .. import domdiv
-from ..domdiv import cards as domdiv_cards
+from .. import main
+from .. import cards as domdiv_cards
class TestCardDB(unittest.TestCase):
def test_cardread(self):
- options = domdiv.parse_opts([])
+ options = main.parse_opts([])
options.data_path = '.'
- cards = domdiv.read_write_card_data(options)
+ cards = main.read_card_data(options)
self.assertEquals(len(cards), 445)
- print set(c.cardset_tag for c in cards)
valid_cardsets = {
u'base',
u'dominion1stEdition',
@@ -41,18 +40,18 @@ class TestCardDB(unittest.TestCase):
def test_languages(self):
# for now, just test that they load
- options = domdiv.parse_opts(['--language', 'it'])
+ options = main.parse_opts(['--language', 'it'])
options.data_path = '.'
- cards = domdiv.read_write_card_data(options)
+ cards = main.read_card_data(options)
self.assertTrue(cards, 'Italians cards did not read properly')
- cards = domdiv.add_card_text(options, cards, 'en_us')
- cards = domdiv.add_card_text(options, cards, 'it')
+ cards = main.add_card_text(options, cards, 'en_us')
+ cards = main.add_card_text(options, cards, 'it')
self.assertIn("Maledizione", [card.name for card in cards])
- options = domdiv.parse_opts(['--language', 'de'])
+ options = main.parse_opts(['--language', 'de'])
options.data_path = '.'
- cards = domdiv.read_write_card_data(options)
+ cards = main.read_card_data(options)
self.assertTrue(cards, 'German cards did not read properly')
- cards = domdiv.add_card_text(options, cards, 'en_us')
- cards = domdiv.add_card_text(options, cards, 'de')
+ cards = main.add_card_text(options, cards, 'en_us')
+ cards = main.add_card_text(options, cards, 'de')
self.assertIn("Fluch", [card.name for card in cards])
diff --git a/tests/codestyle_tests.py b/domdiv/tests/codestyle_tests.py
similarity index 100%
rename from tests/codestyle_tests.py
rename to domdiv/tests/codestyle_tests.py
diff --git a/tests/layout_tests.py b/domdiv/tests/layout_tests.py
similarity index 78%
rename from tests/layout_tests.py
rename to domdiv/tests/layout_tests.py
index 83a0f4d..b11e6cc 100644
--- a/tests/layout_tests.py
+++ b/domdiv/tests/layout_tests.py
@@ -1,5 +1,5 @@
import unittest
-from .. import domdiv
+from .. import main
from reportlab.lib.units import cm
@@ -7,9 +7,9 @@ class TestLayout(unittest.TestCase):
def test_horizontal(self):
# should be the default
- options = domdiv.parse_opts([])
+ options = main.parse_opts([])
self.assertEquals(options.orientation, 'horizontal')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.numDividersHorizontal, 2)
self.assertEquals(options.numDividersVertical, 3)
self.assertEquals(options.dividerWidth, 9.1 * cm)
@@ -17,9 +17,9 @@ class TestLayout(unittest.TestCase):
self.assertEquals(options.dividerHeight, 5.9 * cm + options.labelHeight)
def test_vertical(self):
- options = domdiv.parse_opts(['--orientation', 'vertical'])
+ options = main.parse_opts(['--orientation', 'vertical'])
self.assertEquals(options.orientation, 'vertical')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.numDividersHorizontal, 3)
self.assertEquals(options.numDividersVertical, 2)
self.assertEquals(options.dividerWidth, 5.9 * cm)
@@ -27,8 +27,8 @@ class TestLayout(unittest.TestCase):
self.assertEquals(options.dividerHeight, 9.1 * cm + options.labelHeight)
def test_sleeved(self):
- options = domdiv.parse_opts(['--size', 'sleeved'])
- domdiv.calculate_layout(options)
+ options = main.parse_opts(['--size', 'sleeved'])
+ main.calculate_layout(options)
self.assertEquals(options.dividerWidth, 9.4 * cm)
self.assertEquals(options.labelHeight, 0.9 * cm)
self.assertEquals(options.dividerHeight, 6.15 * cm + options.labelHeight)
diff --git a/tests/text_tab_tests.py b/domdiv/tests/text_tab_tests.py
similarity index 79%
rename from tests/text_tab_tests.py
rename to domdiv/tests/text_tab_tests.py
index bd4f740..b4f6197 100644
--- a/tests/text_tab_tests.py
+++ b/domdiv/tests/text_tab_tests.py
@@ -1,5 +1,5 @@
import unittest
-from .. import domdiv
+from .. import main
class TestTextTabs(unittest.TestCase):
@@ -9,85 +9,85 @@ class TestTextTabs(unittest.TestCase):
####################
def test_text_tabs_default(self):
# should be the default
- options = domdiv.parse_opts([])
+ options = main.parse_opts([])
self.assertEquals(options.text_front, 'card')
self.assertEquals(options.text_back, 'rules')
self.assertEquals(options.tab_name_align, 'left')
self.assertEquals(options.tab_side, 'right-alternate')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'left')
####################
# Card Text Tests
####################
def test_text_card_rules(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--front', 'card', '--back', 'rules'])
self.assertEquals(options.text_front, 'card')
self.assertEquals(options.text_back, 'rules')
def test_text_card_blank(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--front', 'card', '--back', 'blank'])
self.assertEquals(options.text_front, 'card')
self.assertEquals(options.text_back, 'blank')
def test_text_card_card(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--front', 'card', '--back', 'card'])
self.assertEquals(options.text_front, 'card')
self.assertEquals(options.text_back, 'card')
def test_text_card_none(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--front', 'card', '--back', 'none'])
self.assertEquals(options.text_front, 'card')
self.assertEquals(options.text_back, 'none')
def test_text_rules_rules(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--front', 'rules', '--back', 'rules'])
self.assertEquals(options.text_front, 'rules')
self.assertEquals(options.text_back, 'rules')
def test_text_rules_blank(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--front', 'rules', '--back', 'blank'])
self.assertEquals(options.text_front, 'rules')
self.assertEquals(options.text_back, 'blank')
def test_text_rules_card(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--front', 'rules', '--back', 'card'])
self.assertEquals(options.text_front, 'rules')
self.assertEquals(options.text_back, 'card')
def test_text_rules_none(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--front', 'rules', '--back', 'none'])
self.assertEquals(options.text_front, 'rules')
self.assertEquals(options.text_back, 'none')
def test_text_blank_rules(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--front', 'blank', '--back', 'rules'])
self.assertEquals(options.text_front, 'blank')
self.assertEquals(options.text_back, 'rules')
def test_text_blank_blank(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--front', 'blank', '--back', 'blank'])
self.assertEquals(options.text_front, 'blank')
self.assertEquals(options.text_back, 'blank')
def test_text_blank_card(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--front', 'blank', '--back', 'card'])
self.assertEquals(options.text_front, 'blank')
self.assertEquals(options.text_back, 'card')
def test_text_blank_none(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--front', 'blank', '--back', 'none'])
self.assertEquals(options.text_front, 'blank')
self.assertEquals(options.text_back, 'none')
@@ -97,204 +97,204 @@ class TestTextTabs(unittest.TestCase):
####################
# --tab_name_align left
def test_tab_left_left(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'left', '--tab_side', 'left'])
self.assertEquals(options.tab_name_align, 'left')
self.assertEquals(options.tab_side, 'left')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'left')
self.assertEquals(options.tab_side, 'left')
def test_tab_left_right(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'left', '--tab_side', 'right'])
self.assertEquals(options.tab_name_align, 'left')
self.assertEquals(options.tab_side, 'right')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'left')
self.assertEquals(options.tab_side, 'right')
def test_tab_left_leftalt(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'left', '--tab_side',
'left-alternate'])
self.assertEquals(options.tab_name_align, 'left')
self.assertEquals(options.tab_side, 'left-alternate')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'left')
self.assertEquals(options.tab_side, 'left-alternate')
def test_tab_left_rightalt(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'left', '--tab_side',
'right-alternate'])
self.assertEquals(options.tab_name_align, 'left')
self.assertEquals(options.tab_side, 'right-alternate')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'left')
self.assertEquals(options.tab_side, 'right-alternate')
def test_tab_left_full(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'left', '--tab_side', 'full'])
self.assertEquals(options.tab_name_align, 'left')
self.assertEquals(options.tab_side, 'full')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'left')
self.assertEquals(options.tab_side, 'full')
# --tab_name_align right
def test_tab_right_left(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'right', '--tab_side', 'left'])
self.assertEquals(options.tab_name_align, 'right')
self.assertEquals(options.tab_side, 'left')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'right')
self.assertEquals(options.tab_side, 'left')
def test_tab_right_right(self):
- options = domdiv.parse_opts(['--tab_name_align',
- 'right', '--tab_side', 'right'])
+ options = main.parse_opts(['--tab_name_align',
+ 'right', '--tab_side', 'right'])
self.assertEquals(options.tab_name_align, 'right')
self.assertEquals(options.tab_side, 'right')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'right')
self.assertEquals(options.tab_side, 'right')
def test_tab_right_leftalt(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'right', '--tab_side',
'left-alternate'])
self.assertEquals(options.tab_name_align, 'right')
self.assertEquals(options.tab_side, 'left-alternate')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'right')
self.assertEquals(options.tab_side, 'left-alternate')
def test_tab_right_rightalt(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'right', '--tab_side',
'right-alternate'])
self.assertEquals(options.tab_name_align, 'right')
self.assertEquals(options.tab_side, 'right-alternate')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'right')
self.assertEquals(options.tab_side, 'right-alternate')
def test_tab_right_full(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'right', '--tab_side', 'full'])
self.assertEquals(options.tab_name_align, 'right')
self.assertEquals(options.tab_side, 'full')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'right')
self.assertEquals(options.tab_side, 'full')
# --tab_name_align edge
def test_tab_edge_left(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'edge', '--tab_side', 'left'])
self.assertEquals(options.tab_name_align, 'edge')
self.assertEquals(options.tab_side, 'left')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'edge')
self.assertEquals(options.tab_side, 'left')
def test_tab_edge_right(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'edge', '--tab_side', 'right'])
self.assertEquals(options.tab_name_align, 'edge')
self.assertEquals(options.tab_side, 'right')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'edge')
self.assertEquals(options.tab_side, 'right')
def test_tab_edge_leftalt(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'edge', '--tab_side',
'left-alternate'])
self.assertEquals(options.tab_name_align, 'edge')
self.assertEquals(options.tab_side, 'left-alternate')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'edge')
self.assertEquals(options.tab_side, 'left-alternate')
def test_tab_edge_rightalt(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'edge', '--tab_side',
'right-alternate'])
self.assertEquals(options.tab_name_align, 'edge')
self.assertEquals(options.tab_side, 'right-alternate')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'edge')
self.assertEquals(options.tab_side, 'right-alternate')
def test_tab_edge_full(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'edge', '--tab_side', 'full'])
self.assertEquals(options.tab_name_align, 'edge')
self.assertEquals(options.tab_side, 'full')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align,
'left') # special check for odd condition
self.assertEquals(options.tab_side, 'full')
# --tab_name_align centre
def test_tab_centre_left(self):
- options = domdiv.parse_opts(['--tab_name_align',
- 'centre', '--tab_side', 'left'])
+ options = main.parse_opts(['--tab_name_align',
+ 'centre', '--tab_side', 'left'])
self.assertEquals(options.tab_name_align, 'centre')
self.assertEquals(options.tab_side, 'left')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'centre')
self.assertEquals(options.tab_side, 'left')
def test_tab_centre_right(self):
- options = domdiv.parse_opts(['--tab_name_align',
- 'centre', '--tab_side', 'right'])
+ options = main.parse_opts(['--tab_name_align',
+ 'centre', '--tab_side', 'right'])
self.assertEquals(options.tab_name_align, 'centre')
self.assertEquals(options.tab_side, 'right')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'centre')
self.assertEquals(options.tab_side, 'right')
def test_tab_centre_leftalt(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'centre', '--tab_side',
'left-alternate'])
self.assertEquals(options.tab_name_align, 'centre')
self.assertEquals(options.tab_side, 'left-alternate')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'centre')
self.assertEquals(options.tab_side, 'left-alternate')
def test_tab_centre_rightalt(self):
- options = domdiv.parse_opts(
+ options = main.parse_opts(
['--tab_name_align', 'centre', '--tab_side',
'right-alternate'])
self.assertEquals(options.tab_name_align, 'centre')
self.assertEquals(options.tab_side, 'right-alternate')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'centre')
self.assertEquals(options.tab_side, 'right-alternate')
def test_tab_centre_full(self):
- options = domdiv.parse_opts(['--tab_name_align',
- 'centre', '--tab_side', 'full'])
+ options = main.parse_opts(['--tab_name_align',
+ 'centre', '--tab_side', 'full'])
self.assertEquals(options.tab_name_align, 'centre')
self.assertEquals(options.tab_side, 'full')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align, 'centre')
self.assertEquals(options.tab_side, 'full')
# --tab_name_align center. Just do one since this is an alias to centre
def test_tab_center_left(self):
- options = domdiv.parse_opts(['--tab_name_align',
- 'center', '--tab_side', 'left'])
+ options = main.parse_opts(['--tab_name_align',
+ 'center', '--tab_side', 'left'])
self.assertEquals(options.tab_name_align, 'center')
self.assertEquals(options.tab_side, 'left')
- domdiv.calculate_layout(options)
+ main.calculate_layout(options)
self.assertEquals(options.tab_name_align,
'centre') # check for change in value
self.assertEquals(options.tab_side, 'left')
diff --git a/dominion_dividers.py b/dominion_dividers.py
deleted file mode 100644
index a1d4498..0000000
--- a/dominion_dividers.py
+++ /dev/null
@@ -1,6 +0,0 @@
-import domdiv
-import os
-import sys
-
-if __name__ == '__main__':
- domdiv.main(sys.argv[1:], os.path.dirname(__file__))
diff --git a/setup.py b/setup.py
index fe1e060..b3b8b32 100644
--- a/setup.py
+++ b/setup.py
@@ -1,8 +1,8 @@
-from __init__ import __version__
+from domdiv import __version__
from setuptools import setup, find_packages
setup(
- name="dominiontabs",
+ name="domdiv",
version=__version__,
entry_points={
'console_scripts': [
@@ -12,9 +12,7 @@ setup(
packages=find_packages(exclude=['tests']),
install_requires=["reportlab>=2.5",
"Pillow>=2.1.0"],
- package_data={
- 'domdiv': ['images/*.png', 'card_db/*/*.json']
- },
+ include_package_data=True,
author="Sumpfork",
author_email="sumpfork@mailmight.net",
description="Divider Generation for the Dominion Card Game"