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()
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)
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()
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()
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
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()
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)
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
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
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)