oskusalerma / blyte

Screenplay writing program

blyte / pml.py
100644 132 lines (104 sloc) 3.86 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# PML is short for Page Modeling Language, our own neat little PDF-wannabe
# format for expressing a script's complete contents in a neutral way
# that's easy to render to almost anything, e.g. PDF, Postscript, Windows
# GDI, etc.
#
 
# A PML document is a collection of pages plus possibly some metadata.
# Each page is a collection of simple drawing commands, executed
# sequentially in the order given, assuming "complete overdraw" semantics
# on the output device, i.e. whatever is drawn completely covers things it
# is painted on top of.
 
# All measurements in PML are in (floating point) millimeters.
 
import util
 
# types of drawing operations
OP_TEXT = 0
OP_LINE = 1
OP_RECT = 2
OP_PDF = 3
 
# text flags. don't change these unless you know what you're doing.
NORMAL = 0
BOLD = 1
ITALIC = 2
COURIER = 0
TIMES_ROMAN = 4
HELVETICA = 8
UNDERLINED = 16
 
# A single document.
class Document:
 
    # (w, h) is the size of each page.
    def __init__(self, w, h):
        self.w = w
        self.h = h
        
        # a collection of Page objects
        self.pages = []
 
    def add(self, page):
        self.pages.append(page)
 
class Page:
    def __init__(self, doc):
 
        # link to containing document
        self.doc = doc
        
        # a collection of Operation objects
        self.ops = []
 
    def add(self, op):
        self.ops.append(op)
 
# An abstract base class for all drawing operations.
class DrawOp:
    def __init__(self, type):
        self.type = type
 
# Draw text string 'text', at position (x, y) mm from the upper left
# corner of the page. Font used is 'size' points, and Courier / Times/
# Helvetica as indicated by the flags, possibly being bold / italic /
# underlined.
class TextOp(DrawOp):
    def __init__(self, text, x, y, size, flags = NORMAL | COURIER,
                 align = util.ALIGN_LEFT, valign = util.VALIGN_TOP):
        DrawOp.__init__(self, OP_TEXT)
 
        self.text = text
        self.x = x
        self.y = y
        self.size = size
        self.flags = flags
 
        if align != util.ALIGN_LEFT:
            w = util.getTextWidth(text, flags, size)
 
            if align == util.ALIGN_CENTER:
                self.x -= w / 2
            elif align == util.ALIGN_RIGHT:
                self.x -= w
 
        if valign != util.VALIGN_TOP:
            h = util.getTextHeight(size)
            
            if valign == util.VALIGN_CENTER:
                self.y -= h / 2
            elif valign == util.VALIGN_BOTTOM:
                self.y -= h
 
# Draw consecutive lines. 'points' is a list of (x, y) pairs (minimum 2
# pairs) and 'width' is the line width, with 0 being the thinnest possible
# line. if 'isClosed' is True, the last point on the list is connected to
# the first one.
class LineOp(DrawOp):
    def __init__(self, points, width, isClosed = False):
        DrawOp.__init__(self, OP_LINE)
 
        self.points = points
        self.width = width
        self.isClosed = isClosed
 
# helper function for creating simple lines
def genLine(x, y, xd, yd, width):
    return LineOp([(x, y), (x + xd, y + yd)], width)
 
# Draw a rectangle, possibly filled, with specified lineWidth. (x, y) is
# position of upper left corner. Line width of filled rectangles is
# ignored.
class RectOp(DrawOp):
    def __init__(self, x, y, width, height, lineWidth, isFilled = False):
        DrawOp.__init__(self, OP_RECT)
 
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.lw = lineWidth
        self.isFilled = isFilled
 
# Arbitrary PDF commands. Should not have whitespace in the beginning or
# the end. Should be used only for non-critical things like tweaking line
# join styles etc, because non-PDF renderers will ignore these.
class PDFOp(DrawOp):
    def __init__(self, cmds):
        DrawOp.__init__(self, OP_PDF)
 
        self.cmds = cmds