예제 #1
0
    def get_bbox(self):
        """Returns the inherent (data) bounding box of the layer

        :rtype: lib.helpers.Rect

        The returned rectangle is tile-aligned. It's just a default (zero-size)
        rect in the base implementation.
        """
        return helpers.Rect()
예제 #2
0
 def _content_changed_aggregated(self, bboxes):
     """Aggregated content-change notification"""
     if self.root is None:
         return
     redraw_bbox = helpers.Rect()
     for bbox in bboxes:
         if bbox.w == 0 and bbox.h == 0:
             redraw_bbox = bbox
             break
         redraw_bbox.expandToIncludeRect(bbox)
     self._content_changed(*redraw_bbox)
예제 #3
0
    def get_bbox(self):
        """Returns the inherent (data) bounding box of the layer

        :rtype: lib.helpers.Rect

        The returned rectangle is generally tile-aligned, but isn't
        required to be. In this base implementation, the returned bbox
        is a zero-size default Rect, which is also how a full redraw is
        signalled. Subclasses should override this with a better
        implementation.

        The data bounding box is used for certain classes of redraws.
        See also get_full_redraw_bbox().

        """
        return helpers.Rect()
예제 #4
0
    def get_full_redraw_bbox(self):
        """Returns the full update notification bounding box of the layer

        :rtype: lib.helpers.Rect

        This is the bounding box which should be used for redrawing if a
        layer-wide property like opacity or combining mode changes.
        Normally this is the layer's data bounding box, which allows the
        GUI to skip empty tiles when redrawing the layer stack. If
        instead the layer's compositing mode means that an opacity of
        zero affects the backdrop regardless, then the returned bbox is
        a zero-size rectangle, which is the signal for a full redraw.
        """
        if self.mode in MODES_EFFECTIVE_AT_ZERO_ALPHA:
            return helpers.Rect()
        else:
            return self.get_bbox()
예제 #5
0
def combine_redraws(bboxes):
    """Combine multiple rectangles representing redraw areas into one

    :param iterable bboxes: Sequence of redraw bboxes (lib.helpers.Rect)
    :returns: A single redraw bbox.
    :rtype: lib.helpers.Rect

    This is best used for small, related redraws, since the GUI may have
    better ways of combining rectangles into update regions.  Pairs of
    before and after states are good candidates for using this.

    If any of the input bboxes have zero size, the first such bbox is
    returned. Zero-size update bboxes are the conventional way of
    requesting a full-screen update.

    """
    redraw_bbox = helpers.Rect()
    for bbox in bboxes:
        if bbox.w == 0 and bbox.h == 0:
            return bbox
        redraw_bbox.expandToIncludeRect(bbox)
    return redraw_bbox
예제 #6
0
    def get_full_redraw_bbox(self):
        """Gets the full update notification bounding box of the layer

        :rtype: lib.helpers.Rect

        This is the appropriate bounding box for redraws if a layer-wide
        property like visibility or combining mode changes.

        Normally this is the layer's inherent data bounding box, which
        allows the GUI to skip outlying empty tiles when redrawing the
        layer stack.  If instead the layer's compositing mode dictates
        that a calculated pixel alpha of zero would affect the backdrop
        regardless - something that's true of certain masking modes -
        then the returned bbox is a zero-size rectangle, which is the
        signal for a full redraw.

        See also get_bbox().

        """
        if self.mode in MODES_EFFECTIVE_AT_ZERO_ALPHA:
            return helpers.Rect()
        else:
            return self.get_bbox()
예제 #7
0
    def _tile_is_visible(self, tx, ty, transformation, clip_rect,
                         translation_only):
        """Tests whether an individual tile is visible.

        This is sometimes worth doing during rendering, but not always.
        Currently we use _render_get_clip_region()'s sparse flag to
        determine whether this is necessary. The original logic for
        this function was documented as...

        > it is worth checking whether this tile really will be visible
        > (to speed up the L-shaped expose event during scrolling)
        > (speedup clearly visible; slowdown measurable when always
        > executing this code)

        I'm not 100% certain that GTK3 does panning redraws this way,
        so perhaps this method is uneccessary for those?
        However this method is always used when rendering during
        painting, or other activities that send partial updates.

        """
        N = tiledsurface.N
        if translation_only:
            x, y = transformation.transform_point(tx*N, ty*N)
            bbox = (int(x), int(y), N, N)
        else:
            corners = [
                (tx*N, ty*N), ((tx+1)*N, ty*N),
                (tx*N, (ty+1)*N), ((tx+1)*N, (ty+1)*N),
            ]
            corners = [
                transformation.transform_point(x_, y_)
                for (x_, y_) in corners
            ]
            bbox = helpers.rotated_rectangle_bbox(corners)
        tile_rect = helpers.Rect(*bbox)
        return clip_rect.overlaps(tile_rect)
예제 #8
0
 def get_bbox(self):
     """Returns the inherent (data) bounding box of the stack"""
     result = helpers.Rect()
     for layer in self._layers:
         result.expandToIncludeRect(layer.get_bbox())
     return result
예제 #9
0
    def _render_get_clip_region(self, cr, device_bbox):
        """Get the area that needs to be updated, in device coords.

        Called when handling "draw" events.  This uses Cairo's clip
        region, which ultimately derives from the areas sent by
        lib.document.Document.canvas_area_modified().  These can be
        small or large if the update comes form the user drawing
        something. When panning or zooming the canvas, it's a full
        redraw, and the area corresponds to the entire display.

        :param cairo.Context cr: as passed to the "draw" event handler.
        :param tuple device_bbox: (x,y,w,h) widget extents
        :returns: (clipregion, sparse)
        :rtype: tuple

        The clip region return value is a lib.helpers.Rect containing
        the area to redraw in display coordinates, or None.

        This also determines whether the redraw is "sparse", meaning
        that the clip region returned does not contain the centre of the
        device bbox.

        """

        # Could this be an alternative?
        #x0, y0, x1, y1 = cr.clip_extents()
        #sparse = True
        #clip_region = (x0, y0, x1-x0, y1-y0)
        #return clip_region, sparse

        # Get the area which needs to be updated, in device coordinates, and
        # determine whether the render is "sparse", [TODO: define what this
        # means]
        x, y, w, h = device_bbox
        cx, cy = x+w/2, y+h/2

        # As of 2012-07-08, Ubuntu Precise (LTS, unfortunately) and Debian
        # unstable(!) use python-cairo 1.8.8, which does not support
        # the cairo.Region return from Gdk.Window.get_clip_region() we
        # really need. They'll be important to support for a while, so we
        # have to use an inefficient workaround using the complete clip
        # rectangle for the update.
        #
        # http://stackoverflow.com/questions/6133622/
        # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=653588
        # http://packages.ubuntu.com/python-cairo
        # http://packages.debian.org/python-cairo
        #
        # Update 2015-08-14: actually, on Debian-derived systems you
        # need gir1.2-freedesktop 1.44.0, which contains a wrapping for
        # some cairoish return values from GTK/GDK, including
        # CairoRegion: cairo-1.0.typelib. On MSYS2, ensure you have
        # mingw-w64-i686-gobject-introspection-runtime or its x86_64
        # equivalent installed, also at version 1.44.

        clip_exists, rect = gdk.cairo_get_clip_rectangle(cr)
        if clip_exists:
            # It's a wrapped cairo_rectangle_int_t, CairoRectangleInt
            # Convert to a better representation for our purposes,
            # noting https://github.com/mypaint/mypaint/issues/433
            rect = helpers.Rect(rect.x, rect.y, rect.width, rect.height)
            sparse = (
                cx < rect.x
                or cx > (rect.x + rect.w)
                or cy < rect.y
                or cy > (rect.y + rect.h)
            )
        else:
            rect = None
            sparse = False

        return rect, sparse
예제 #10
0
 def queue_draw_area(self, x, y, w, h):
     if self._idle_redraw_priority is None:
         gtk.DrawingArea.queue_draw_area(self, x, y, w, h)
         return
     bbox = helpers.Rect(x, y, w, h)
     self._queue_idle_redraw(bbox)