platypus: change implementation of new FrameBG so it can be used in containers
authorrobin
Wed, 03 Jul 2013 16:06:50 +0100
changeset 3706 d468d1f4e8b7
parent 3705 9b5c64be3aa4
child 3707 961300bcfe84
platypus: change implementation of new FrameBG so it can be used in containers
src/reportlab/platypus/__init__.py
src/reportlab/platypus/doctemplate.py
src/reportlab/platypus/flowables.py
src/reportlab/platypus/frames.py
tests/test_platypus_pleaseturnover.py
--- a/src/reportlab/platypus/__init__.py	Wed Jul 03 16:04:50 2013 +0100
+++ b/src/reportlab/platypus/__init__.py	Wed Jul 03 16:06:50 2013 +0100
@@ -6,12 +6,11 @@
 
 from reportlab.platypus.flowables import Flowable, Image, Macro, PageBreak, Preformatted, Spacer, XBox, \
                         CondPageBreak, KeepTogether, TraceInfo, FailOnWrap, FailOnDraw, PTOContainer, \
-                        KeepInFrame, ParagraphAndImage, ImageAndFlowables, ListFlowable, ListItem
+                        KeepInFrame, ParagraphAndImage, ImageAndFlowables, ListFlowable, ListItem, FrameBG
 from reportlab.platypus.paragraph import Paragraph, cleanBlockQuotedText, ParaLines
 from reportlab.platypus.paraparser import ParaFrag
 from reportlab.platypus.tables import Table, TableStyle, CellStyle, LongTable
 from reportlab.platypus.frames import Frame
 from reportlab.platypus.doctemplate import BaseDocTemplate, NextPageTemplate, PageTemplate, ActionFlowable, \
-                        SimpleDocTemplate, FrameBreak, PageBegin, Indenter, NotAtTopPageBreak, \
-                        FrameBG
+                        SimpleDocTemplate, FrameBreak, PageBegin, Indenter, NotAtTopPageBreak
 from xpreformatted import XPreformatted
--- a/src/reportlab/platypus/doctemplate.py	Wed Jul 03 16:04:50 2013 +0100
+++ b/src/reportlab/platypus/doctemplate.py	Wed Jul 03 16:06:50 2013 +0100
@@ -233,26 +233,6 @@
         frame._leftExtraIndent += self.left
         frame._rightExtraIndent += self.right
 
-class FrameBG(FrameActionFlowable):
-    """Start or stop coloring the frame background
-    left & right are distances from the edge of the frame to start stop colouring.
-    """
-    _ZEROSIZE=True
-    width=0
-    height=0
-    def __init__(self, color=None, left=0, right=0, start=True):
-        self.start = start
-        if start:
-            self.left = _evalMeasurement(left)
-            self.right = _evalMeasurement(right)
-            self.color = color
-
-    def frameAction(self, frame):
-        if self.start:
-            frame._frameBGs.append((self.left,self.right,self.color))
-        elif frame._frameBGs:
-            frame._frameBGs.pop()
-
 class NotAtTopPageBreak(FrameActionFlowable):
     def __init__(self):
         pass
--- a/src/reportlab/platypus/flowables.py	Wed Jul 03 16:04:50 2013 +0100
+++ b/src/reportlab/platypus/flowables.py	Wed Jul 03 16:06:50 2013 +0100
@@ -830,6 +830,7 @@
     def drawOn(self, canv, x, y, _sW=0, scale=1.0, content=None, aW=None):
         '''we simulate being added to a frame'''
         from doctemplate import ActionFlowable, Indenter
+        x0 = x
         pS = 0
         if aW is None: aW = self.width
         aW *= scale
@@ -837,6 +838,7 @@
             content = self._content
         x = self._hAlignAdjust(x,_sW*scale)
         y += self.height*scale
+        frame = getattr(self,'_frame',None)
         for c in content:
             if not ignoreContainerActions and isinstance(c,ActionFlowable):
                 c.apply(self.canv._doctemplate)
@@ -849,10 +851,22 @@
             if (w<_FUZZ or h<_FUZZ) and not getattr(c,'_ZEROSIZE',None): continue
             if c is not content[0]: h += max(c.getSpaceBefore()-pS,0)
             y -= h
+            fbg = getattr(frame,'_frameBGs',None)
+            pS = c.getSpaceAfter()
+            if fbg:
+                fbgl, fbgr, fbgc = fbg[-1]
+                fbw = scale*(frame._width-fbgl-fbgr)
+                fbh = h+pS
+                if abs(fbw)>_FUZZ and abs(fbh)>_FUZZ:
+                    canv.saveState()
+                    canv.setFillColor(fbgc)
+                    canv.rect(x0+scale*(fbgl-frame._leftPadding)-0.1,y-pS-0.1,fbw+0.2,fbh+0.2,stroke=0,fill=1)
+                    canv.restoreState()
+            c._frame = frame
             c.drawOn(canv,x,y,_sW=aW-w)
             if c is not content[-1]:
-                pS = c.getSpaceAfter()
                 y -= pS
+            del c._frame
 
     def copyContent(self,content=None):
         C = [].append
@@ -1272,6 +1286,31 @@
     def draw(self):
         self.canv.bookmarkHorizontal(self._name,0,0)
 
+class FrameBG(AnchorFlowable):
+    """Start or stop coloring the frame background
+    left & right are distances from the edge of the frame to start stop colouring.
+    """
+    _ZEROSIZE=1
+    def __init__(self, color=None, left=0, right=0, start=True):
+        Spacer.__init__(self,0,0)
+        self.start = start
+        if start:
+            from reportlab.platypus.doctemplate import _evalMeasurement
+            self.left = _evalMeasurement(left)
+            self.right = _evalMeasurement(right)
+            self.color = color
+
+    def __repr__(self):
+        return "%s(%s)" % (self.__class__.__name__,', '.join(['%s=%r' % (i,getattr(self,i,None)) for i in 'start color left right'.split()]))
+
+    def draw(self):
+        frame = getattr(self,'_frame',None)
+        if frame is None: return
+        if self.start:
+            frame._frameBGs.append((self.left,self.right,self.color))
+        elif frame._frameBGs:
+            frame._frameBGs.pop()
+
 class FrameSplitter(NullDraw):
     '''When encountered this flowable should either switch directly to nextTemplate
     if remaining space in the current frame is less than gap+required or it should
--- a/src/reportlab/platypus/frames.py	Wed Jul 03 16:04:50 2013 +0100
+++ b/src/reportlab/platypus/frames.py	Wed Jul 03 16:06:50 2013 +0100
@@ -175,10 +175,13 @@
                 fbg = getattr(self,'_frameBGs',None)
                 if fbg:
                     fbgl, fbgr, fbgc = fbg[-1]
-                    canv.saveState()
-                    canv.setFillColor(fbgc)
-                    canv.rect(self._x1+fbgl,y-s,self._width-fbgl-fbgr,h+s,stroke=0,fill=1)
-                    canv.restoreState()
+                    fbw = self._width-fbgl-fbgr
+                    fbh = h+s
+                    if abs(fbw)>_FUZZ and abs(fbh)>_FUZZ:
+                        canv.saveState()
+                        canv.setFillColor(fbgc)
+                        canv.rect(self._x1+fbgl,y-s,fbw,fbh,stroke=0,fill=1)
+                        canv.restoreState()
 
                 flowable.drawOn(canv, self._x + self._leftExtraIndent, y, _sW=aW-w)
                 flowable.canv=canv
--- a/tests/test_platypus_pleaseturnover.py	Wed Jul 03 16:04:50 2013 +0100
+++ b/tests/test_platypus_pleaseturnover.py	Wed Jul 03 16:06:50 2013 +0100
@@ -8,6 +8,7 @@
 import sys
 import unittest
 from reportlab.platypus.flowables import Flowable, PTOContainer, KeepInFrame
+from reportlab.platypus import FrameBG
 from reportlab.lib.units import cm
 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
 from reportlab.lib.colors import toColor, black
@@ -160,15 +161,20 @@
     H1.pageBreakBefore = 0
     H1.keepWithNext = 0
     bt = styleSheet['BodyText']
-    def subStory(texts):
+    def subStory(texts,fbg=0):
         style = [
             ('VALIGN',(0,0),(-1,-1),'TOP'),
             ('INNERGRID', (0,0), (-1,-1), 0.25, black),
             ('BOX', (0,0), (-1,-1), 0.25, black),
             ]
+        if fbg:
+            fbg1 = [FrameBG(start=0,color=toColor('limegreen'))]
+            fbg0 = [FrameBG(start=0)]
+        else:
+            fbg0 = fbg1 = []
         return ([Paragraph(t,bt) for t in texts]
-                +[Table([('alignment', a.lower())],style = style,hAlign=a)
-                    for a in ('LEFT','RIGHT','CENTER')])
+                +fbg1+[Table([('alignment', a.lower())],style = style,hAlign=a)
+                    for a in ('LEFT','RIGHT','CENTER')]+fbg0)
     def allModesKIF(just,ifb=True,width=170):
         if ifb: fbreak()
         story.append(KeepInFrame(width-offset,284-offset,subStory(texts=(text0,)),mode=mode,hAlign=just))
@@ -176,6 +182,8 @@
         story.append(KeepInFrame(width-offset,284-offset,subStory(texts=(text0,text1)),mode=mode,hAlign=just))
         fbreak()
         story.append(KeepInFrame(width-offset,284-offset,subStory(texts=(text0,text1,text2)),mode=mode,hAlign=just))
+        fbreak()
+        story.append(KeepInFrame(width-offset,284-offset,subStory(texts=(text0,text1,text2),fbg=1),mode=mode,hAlign=just))
     allModesKIF('LEFT',False)
     allModesKIF('LEFT',width=100)
     allModesKIF('CENTRE',width=100)