flowables.py & frames.py: attempt to improve handling of various Zero size flowables py33
authorrobin
Mon, 29 Jul 2013 13:36:20 +0100
branchpy33
changeset 3750 63d5d0c8665e
parent 3749 8b6518bd2a57
child 3751 1809185f0a36
flowables.py & frames.py: attempt to improve handling of various Zero size flowables
src/reportlab/platypus/flowables.py
src/reportlab/platypus/frames.py
--- a/src/reportlab/platypus/flowables.py	Mon Jul 29 13:35:34 2013 +0100
+++ b/src/reportlab/platypus/flowables.py	Mon Jul 29 13:36:20 2013 +0100
@@ -585,12 +585,18 @@
             H += h
             if not atTop:
                 h = f.getSpaceBefore()
-                if mergeSpace: h = max(h-pS,0)
+                if mergeSpace:
+                    if getattr(f,'_SPACETRANSFER',False):
+                        h = pS
+                    h = max(h-pS,0)
                 H += h
             else:
                 if obj is not None: obj._spaceBefore = f.getSpaceBefore()
                 atTop = 0
-            pS = f.getSpaceAfter()
+            s = f.getSpaceAfter()
+            if getattr(f,'_SPACETRANSFER',False):
+                s = pS
+            pS = s
             H += pS
         if obj is not None: obj._spaceAfter = pS
         return W, H-pS
@@ -831,6 +837,8 @@
     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
+        y0 = y
         pS = 0
         if aW is None: aW = self.width
         aW *= scale
@@ -838,6 +846,8 @@
             content = self._content
         x = self._hAlignAdjust(x,_sW*scale)
         y += self.height*scale
+        yt = y
+        frame = getattr(self,'_frame',None)
         for c in content:
             if not ignoreContainerActions and isinstance(c,ActionFlowable):
                 c.apply(self.canv._doctemplate)
@@ -848,11 +858,30 @@
                 continue
             w, h = c.wrapOn(canv,aW,0xfffffff)
             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)
+            if yt!=y:
+                s = c.getSpaceBefore()
+                if not getattr(c,'_SPACETRANSFER',False):
+                    h += max(s-pS,0)
             y -= h
+            fbg = getattr(frame,'_frameBGs',None)
+            s = c.getSpaceAfter()
+            if getattr(c,'_SPACETRANSFER',False):
+                s = pS
+            pS = s
+            if fbg:
+                fbgl, fbgr, fbgc = fbg[-1]
+                fbw = scale*(frame._width-fbgl-fbgr)
+                fbh = y + h + pS
+                fby = max(y0,y-pS)
+                fbh = max(0,fbh-fby)
+                if abs(fbw)>_FUZZ and abs(fbh)>_FUZZ:
+                    canv.saveState()
+                    canv.setFillColor(fbgc)
+                    canv.rect(x0+scale*(fbgl-frame._leftPadding)-0.1,fby-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()
+            if c is not content[-1] and not getattr(c,'_SPACETRANSFER',None):
                 y -= pS
 
     def copyContent(self,content=None):
@@ -1260,6 +1289,7 @@
 class AnchorFlowable(Spacer):
     '''create a bookmark in the pdf'''
     _ZEROSIZE=1
+    _SPACETRANSFER = True
     def __init__(self,name):
         Spacer.__init__(self,0,0)
         self._name = name
@@ -1273,6 +1303,32 @@
     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:
+            w = getattr(frame,'_lineWidth',0)
+            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	Mon Jul 29 13:35:34 2013 +0100
+++ b/src/reportlab/platypus/frames.py	Mon Jul 29 13:36:20 2013 +0100
@@ -153,6 +153,8 @@
             if not self._atTop:
                 s =flowable.getSpaceBefore()
                 if self._oASpace:
+                    if getattr(flowable,'_SPACETRANSFER',False):
+                        s = self._prevASpace
                     s = max(s-self._prevASpace,0)
             h = y - p - s
             if h>0:
@@ -171,12 +173,29 @@
                 return 0
             else:
                 #now we can draw it, and update the current point.
+                s = flowable.getSpaceAfter()
+                fbg = getattr(self,'_frameBGs',None)
+                if fbg:
+                    fbgl, fbgr, fbgc = fbg[-1]
+                    fbw = self._width-fbgl-fbgr
+                    fbh = y + h + s
+                    fby = max(p,y-s)
+                    fbh = max(0,fbh-fby)
+                    if abs(fbw)>_FUZZ and abs(fbh)>_FUZZ:
+                        canv.saveState()
+                        canv.setFillColor(fbgc)
+                        canv.rect(self._x1+fbgl,fby,fbw,fbh,stroke=0,fill=1)
+                        canv.restoreState()
+
                 flowable.drawOn(canv, self._x + self._leftExtraIndent, y, _sW=aW-w)
                 flowable.canv=canv
                 if self._debug: logger.debug('drew %s' % flowable.identity())
                 s = flowable.getSpaceAfter()
                 y -= s
-                if self._oASpace: self._prevASpace = s
+                if self._oASpace:
+                    if getattr(flowable,'_SPACETRANSFER',False):
+                        s = self._prevASpace
+                    self._prevASpace = s
                 if y!=self._y: self._atTop = 0
                 self._y = y
                 return 1
@@ -208,11 +227,12 @@
                     delattr(flowable,a)
         return r
 
+
     def drawBoundary(self,canv):
         "draw the frame boundary as a rectangle (primarily for debugging)."
-        from reportlab.lib.colors import Color, CMYKColor, toColor
+        from reportlab.lib.colors import Color, toColor
         sb = self.showBoundary
-        ss = type(sb) in (type(''),type(()),type([])) or isinstance(sb,Color)
+        ss = isinstance(sb,(str,tuple,list)) or isinstance(sb,Color)
         w = -1
         if ss:
             c = toColor(sb,self)