summaryrefslogtreecommitdiff
path: root/ptlayout.py
diff options
context:
space:
mode:
Diffstat (limited to 'ptlayout.py')
-rw-r--r--ptlayout.py170
1 files changed, 170 insertions, 0 deletions
diff --git a/ptlayout.py b/ptlayout.py
new file mode 100644
index 0000000..f9518b7
--- /dev/null
+++ b/ptlayout.py
@@ -0,0 +1,170 @@
+#!/usr/bin/env python
+# vim: set expandtab ts=4:
+
+import cairo, pango, pangocairo
+import qrcode
+from math import pi
+
+dummysurface = cairo.ImageSurface(cairo.FORMAT_A1, 1, 1)
+dummyctx = cairo.Context(dummysurface)
+
+class PTLayoutElem(object):
+ def __init__(self):
+ super(PTLayoutElem, self).__init__()
+
+ def prep_size(self, h):
+ return (0, 0)
+
+ def render(self, cctx, h):
+ return 0
+
+ def children(self):
+ return []
+
+ def properties(self):
+ return []
+
+class PTLText(PTLayoutElem):
+ def __init__(self):
+ super(PTLText, self).__init__()
+ self.text = ''
+ self.font = ''
+ self.mode = ''
+
+ def properties(self):
+ return [
+ ('text', 'text'),
+ ('font', 'text'),
+ ('mode', 'text'),
+ ]
+
+ def prep_size(self, h):
+ return self._render(dummyctx, True, h)
+
+ def render(self, cctx, h):
+ return self._render(cctx, False, h)
+
+ def _render(self, cctx, sizeonly, h):
+ pctx = pangocairo.CairoContext(cctx)
+ font = pango.FontDescription(self.font if self.font != '' else 'Delicious 24')
+ layout = pctx.create_layout()
+ layout.set_font_description(font)
+ layout.set_text(unicode(self.text))
+ size = layout.get_pixel_size()
+ if sizeonly:
+ if self.mode in ['left', 'right']:
+ return (size[1], size[0])
+ return size
+ w = size[0]
+
+ matrix = cctx.get_matrix()
+ if self.mode == 'left':
+ cctx.rotate(90. * pi / 180.)
+ cctx.translate((h - size[0]) / 2, -size[1])
+ w = size[1]
+ elif self.mode == 'right':
+ cctx.rotate(-90. * pi / 180.)
+ cctx.translate(-h + (h - size[0]) / 2, 0)
+ w = size[1]
+
+ pctx.update_layout(layout)
+ pctx.show_layout(layout)
+
+ cctx.set_matrix(matrix)
+ return w
+
+class PTLQRCode(PTLayoutElem):
+ def __init__(self):
+ super(PTLQRCode, self).__init__()
+ self.qrcontent = ''
+ self.hborder = 4
+ self.invert = True
+
+ def properties(self):
+ return [
+ ('qrcontent', 'text'),
+ ]
+
+ def prep_size(self, h):
+ return self._render(dummyctx, True, h)
+
+ def render(self, cctx, h):
+ return self._render(cctx, False, h)
+
+ def _render(self, cctx, sizeonly, h):
+ qr = qrcode.QRCode(border = 0)
+ qr.add_data(self.qrcontent)
+ qr.make(fit = True)
+ qm = qr.get_matrix()
+ qmlen = len(qm)
+ bpp = h / qmlen
+ if sizeonly: return (bpp * qmlen + self.hborder * 2, bpp * qmlen)
+
+ if self.invert:
+ cctx.rectangle(0, 0, bpp * qmlen + self.hborder * 2, h)
+ cctx.fill()
+ cctx.set_source_rgba(1.0, 1.0, 1.0, 0.0)
+
+ yoffs = (h - bpp * qmlen) / 2
+ for y, line in enumerate(qm):
+ for x, dot in enumerate(line):
+ if dot:
+ cctx.rectangle(bpp * x + self.hborder, bpp * y + yoffs, bpp, bpp)
+ cctx.fill()
+
+ cctx.set_source_rgba(0.0, 0.0, 0.0, 1.0)
+ return bpp * qmlen
+
+class PTLContainer(PTLayoutElem):
+ def __init__(self):
+ super(PTLContainer, self).__init__()
+ self._children = []
+
+ def children(self):
+ return self._children
+
+ def add(self, child):
+ self._children.append(child)
+
+class PTLHSeq(PTLContainer):
+ def __init__(self):
+ super(PTLHSeq, self).__init__()
+ self.spacing = 5
+
+ def prep_size(self, hh):
+ w, h = len(self._children) * self.spacing, 0
+ for k in self._children:
+ cw, ch = k.prep_size(hh)
+ w += cw
+ h = max(h, ch)
+ return (w, h)
+
+ def render(self, cctx, h):
+ wpos = 0
+ for k in self._children:
+ cw = k.render(cctx, h)
+ wpos += cw + self.spacing
+ cctx.translate(cw + self.spacing, 0)
+ cctx.translate(-wpos, 0)
+ return wpos - self.spacing
+
+class PTLVStack(PTLContainer):
+ def __init__(self):
+ super(PTLVStack, self).__init__()
+
+ def prep_size(self, hh):
+ w = 0
+ for k in self._children:
+ cw, ch = k.prep_size(hh / len(self._children))
+ w = max(w, cw)
+ return (w, hh)
+
+ def render(self, cctx, h):
+ w = 0
+ for i, k in enumerate(self._children):
+ vpos = int(h / float(len(self._children)) * i)
+ cctx.translate(0, vpos)
+ cw = k.render(cctx, h)
+ w = max(cw, w)
+ cctx.translate(0, -vpos)
+ return w