#!/usr/bin/env python 
#@+leo-ver=4-thin
#@+node:tbrown.20070622094435.1:@thin pageframe.py
"""Create n-up SVG layouts"""

#@+others
#@+node:tbrown.20070622103716:imports
import sys, inkex

try:
    import xml.etree.ElementTree as ElementTree
except:
    try:
        from lxml import etree as ElementTree
    except:
        try:
            from elementtree.ElementTree import ElementTree
        except:
            sys.stderr.write("""Requires ElementTree module, included
in Python 2.5 or supplied by lxml or elementtree modules.

""")
#@-node:tbrown.20070622103716:imports
#@+node:tbrown.20070622103716.1:expandTuple
def expandTuple(unit, x, length = 4):
    try:
        iter(x)
    except:
        return None

    if len(x) != length: x = x*2
    if len(x) != length:
        raise Exception("expandTuple: requires 2 or 4 item tuple")
    try:
        return tuple(map(lambda ev: (inkex.unittouu(str(eval(str(ev)))+unit)), x))
    except:
        return None
#@-node:tbrown.20070622103716.1:expandTuple
#@+node:tbrown.20070622103716.2:GenerateNup
def GenerateNup(unit="px",
                pgSize=("8.5*90","11*90"),
                pgMargin=(0,0),
                pgPadding=(0,0),
                num=(2,2),
                calculateSize=True,
                size=None,
                margin=(0,0),
                padding=(20,20),
                show=['default'],
                container='svg',
                returnTree = False,
                ):
    """Generate the SVG.  Inputs are run through 'eval(str(x))' so you can use
'8.5*72' instead of 612.  Margin / padding dimension tuples can be
(top & bottom, left & right) or (top, right, bottom, left).

Keyword arguments:
pgSize -- page size, width x height
pgMargin -- extra space around each page
pgPadding -- added to pgMargin
n -- rows x cols
size -- override calculated size, width x height
margin -- white space around each piece
padding -- inner padding for each piece
show -- list of keywords indicating what to show
        - 'crosses' - cutting guides
        - 'inner' - inner boundary
        - 'outer' - outer boundary
container -- 'svg' or 'g'
returnTree -- whether to return the ElementTree or the string
"""

    if 'default' in show:
        show = set(show).union(['inner', 'innerbox', 'holder', 'crosses'])

    pgMargin = expandTuple(unit, pgMargin)
    pgPadding = expandTuple(unit, pgPadding)
    margin = expandTuple(unit, margin)
    padding = expandTuple(unit, padding)

    pgSize = expandTuple(unit, pgSize, length = 2)
#    num = tuple(map(lambda ev: eval(str(ev)), num))

    pgEdge = map(sum,zip(pgMargin, pgPadding))

    top, right, bottom, left = 0,1,2,3
    width, height = 0,1
    rows, cols = 0,1
    size = expandTuple(unit, size, length = 2)
    if size == None or calculateSize == True or len(size) < 2 or size[0] == 0 or size[1] == 0:
        size = ((pgSize[width]
                 - pgEdge[left] - pgEdge[right]
                 - num[cols]*(margin[left] + margin[right])) / num[cols],
                (pgSize[height]
                 - pgEdge[top] - pgEdge[bottom]
                 - num[rows]*(margin[top] + margin[bottom])) / num[rows]
        )
    else:
        size = expandTuple(unit, size, length = 2)

    # sep is separation between same points on pieces
    sep = (size[width]+margin[right]+margin[left],
           size[height]+margin[top]+margin[bottom])

    style = 'stroke:#000000;stroke-opacity:1;fill:none;fill-opacity:1;'

    padbox = 'rect', {
            'x': str(pgEdge[left] + margin[left] + padding[left]),
            'y': str(pgEdge[top] + margin[top] + padding[top]),
            'width': str(size[width] - padding[left] - padding[right]),
            'height': str(size[height] - padding[top] - padding[bottom]),
            'style': style,
            }
    margbox = 'rect', {
            'x': str(pgEdge[left] + margin[left]),
            'y': str(pgEdge[top] + margin[top]),
            'width': str(size[width]),
            'height': str(size[height]),
            'style': style,
            }

    doc = ElementTree.ElementTree(ElementTree.Element(container,
        {'xmlns:inkscape':"http://www.inkscape.org/namespaces/inkscape",
         'xmlns:xlink':"http://www.w3.org/1999/xlink",
         'width':str(pgSize[width]),
         'height':str(pgSize[height]),
         }))

    sub = ElementTree.SubElement

    root = doc.getroot()

    def makeClones(under, to):
        for r in range(0,num[rows]):
            for c in range(0,num[cols]):
                if r == 0 and c == 0: continue
                sub(under, 'use', {
                    'xlink:href': '#' + to,
                    'transform': 'translate(%f,%f)' %
                    (c*sep[width], r*sep[height])})

    # guidelayer #####################################################
    if set(['inner', 'outer']).intersection(show):
        layer = sub(root, 'g', {'id':'guidelayer',
                                'inkscape:groupmode':'layer'})
        if 'inner' in show:
            padbox[1]['id'] = 'innerguide'
            padbox[1]['style'] = padbox[1]['style'].replace('stroke:#000000',
                                                            'stroke:#8080ff')
            sub(layer, *padbox)
            del padbox[1]['id']
            padbox[1]['style'] = padbox[1]['style'].replace('stroke:#8080ff',
                                                            'stroke:#000000')
            makeClones(layer, 'innerguide')
        if 'outer' in show:
            margbox[1]['id'] = 'outerguide'
            margbox[1]['style'] = padbox[1]['style'].replace('stroke:#000000',
                                                              'stroke:#8080ff')
            sub(layer, *margbox)
            del margbox[1]['id']
            margbox[1]['style'] = padbox[1]['style'].replace('stroke:#8080ff',
                                                              'stroke:#000000')
            makeClones(layer, 'outerguide')

    # crosslayer #####################################################
    if set(['crosses']).intersection(show):
        layer = sub(root, 'g', {'id':'cutlayer',
                                'inkscape:groupmode':'layer'})

        if 'crosses' in show:
            crosslen = 12
            group = sub(layer, 'g', id='cross')
            x,y = 0,0
            path = 'M%f %f' % (x+pgEdge[left] + margin[left],
                               y+pgEdge[top] + margin[top]-crosslen)
            path += ' L%f %f' % (x+pgEdge[left] + margin[left],
                                 y+pgEdge[top] + margin[top]+crosslen)
            path += ' M%f %f' % (x+pgEdge[left] + margin[left]-crosslen,
                                 y+pgEdge[top] + margin[top])
            path += ' L%f %f' % (x+pgEdge[left] + margin[left]+crosslen,
                                 y+pgEdge[top] + margin[top])
            sub(group, 'path', style=style+'stroke-width:0.05',
                d = path, id = 'crossmarker')
            for r in 0, 1:
                for c in 0, 1:
                    if r or c:
                        x,y = c*size[width], r*size[height]
                        sub(group, 'use', {
                            'xlink:href': '#crossmarker',
                            'transform': 'translate(%f,%f)' %
                            (x,y)})
            makeClones(layer, 'cross')

    # clonelayer #####################################################
    layer = sub(root, 'g', {'id':'clonelayer', 'inkscape:groupmode':'layer'})
    makeClones(layer, 'main')

    # mainlayer ######################################################
    layer = sub(root, 'g', {'id':'mainlayer', 'inkscape:groupmode':'layer'})
    group = sub(layer, 'g', {'id':'main'})

    if 'innerbox' in show:
        sub(group, *padbox)
    if 'outerbox' in show:
        sub(group, *margbox)
    if 'holder' in show:
        x, y = (pgEdge[left] + margin[left] + padding[left],
                pgEdge[top] + margin[top] + padding[top])
        w, h = (size[width] - padding[left] - padding[right],
                size[height] - padding[top] - padding[bottom])
        path = 'M%f %f' % (x + w/2., y)
        path += ' L%f %f' % (x + w, y + h/2.)
        path += ' L%f %f' % (x + w/2., y + h)
        path += ' L%f %f' % (x, y + h/2.)
        path += ' Z'
        sub(group, 'path', style=style, d = path)

    if returnTree:
        return doc
    else:
        return ElementTree.tostring(root)

if __name__ == '__main__':
    print GenerateNup(num=(10,3), margin=(5,5), show=['default', 'outer'])
#@-node:tbrown.20070622103716.2:GenerateNup
#@-others
#@-node:tbrown.20070622094435.1:@thin pageframe.py
#@-leo

 	  	 
