#!/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 == 'right': cctx.rotate(90. * pi / 180.) cctx.translate((h - size[0]) / 2, -size[1]) w = size[1] elif self.mode == 'left': cctx.rotate(-90. * pi / 180.) cctx.translate(-h + (h - size[0]) / 2, 0) w = size[1] elif self.mode == 'down': cctx.rotate(pi) cctx.translate(-size[0], -(h + size[1]) / 2) else: cctx.translate(0, (h - size[1]) / 2) 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.vborder = 4 self.invert = False 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, error_correction = qrcode.ERROR_CORRECT_L) qr.add_data(self.qrcontent) qr.make(fit = True) qm = qr.get_matrix() qmlen = len(qm) bpp = (h - self.vborder) / qmlen if sizeonly: return (bpp * qmlen + self.hborder * 2, bpp * qmlen + self.vborder * 2) if self.invert: cctx.rectangle(0, 0, bpp * qmlen + self.hborder * 2, h + self.vborder * 2) 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 + self.hborder * 2 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) return child class PTLHSpace(PTLContainer): def __init__(self): super(PTLHSpace, self).__init__() self.spacing = '5' def prep_size(self, hh): return (int(self.spacing), 0) def render(self, cctx, h): return int(self.spacing) def properties(self): return [ ('spacing', 'text'), ] class PTLHSeq(PTLContainer): def __init__(self): super(PTLHSeq, self).__init__() self.spacing = 5 def prep_size(self, hh): if len(self._children) == 0: return (0,0) w, h = (len(self._children) - 1) * 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 / float(len(self._children))) w = max(cw, w) cctx.translate(0, -vpos) return w