def __init__(self, model: Optional[Model] = None, selection: Selection = None): """Create a new view. Args: model (Model): optional model to be set on construction time. selection (Selection): optional selection object, in case the default selection object (hover/select/focus) is not enough. """ Gtk.DrawingArea.__init__(self) self._dirty_items: Set[Item] = set() self._back_buffer: Optional[cairo.Surface] = None self._back_buffer_needs_resizing = True self._controllers: Set[Gtk.EventController] = set() self.set_can_focus(True) if Gtk.get_major_version() == 3: self.add_events(Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.KEY_PRESS_MASK | Gdk.EventMask.KEY_RELEASE_MASK | Gdk.EventMask.SCROLL_MASK | Gdk.EventMask.STRUCTURE_MASK) self.set_app_paintable(True) else: self.set_draw_func(GtkView.do_draw) self.connect_after("resize", GtkView.on_resize) def alignment_updated(matrix: Matrix) -> None: if self._model: self._matrix *= matrix # type: ignore[misc] self._scrolling = Scrolling(alignment_updated) self._selection = selection or Selection() self._matrix = Matrix() self._painter: Painter = DefaultPainter(self) self._bounding_box_painter: ItemPainterType = ItemPainter( self._selection) self._matrix_changed = False self._qtree: Quadtree[Item, Tuple[float, float, float, float]] = Quadtree() self._model: Optional[Model] = None if model: self.model = model self._selection.add_handler(self.on_selection_update) self._matrix.add_handler(self.on_matrix_update)
def test_lookups(self): qtree = Quadtree((0, 0, 100, 100)) for i in range(100, 10): for j in range(100, 10): qtree.add("%dx%d" % (i, j), (i, j, 10, 10)) for i in range(100, 10): for j in range(100, 10): assert qtree.find_intersect((i+1, j+1, 1, 1)) == ['%dx%d' % (i, j)], \ qtree.find_intersect((i+1, j+1, 1, 1))
def test_get_data(self): """ Extra data may be added to a node: """ qtree = Quadtree((0, 0, 100, 100)) for i in range(0, 100, 10): for j in range(0, 100, 10): qtree.add("%dx%d" % (i, j), (i, j, 10, 10), i+j) for i in range(0, 100, 10): for j in range(0, 100, 10): assert i+j == qtree.get_data("%dx%d" % (i, j))
def test_with_rectangles(self): from gaphas.geometry import Rectangle qtree = Quadtree((0, 0, 100, 100)) for i in range(0, 100, 10): for j in range(0, 100, 10): qtree.add("%dx%d" % (i, j), Rectangle(i, j, 10, 10)) assert len(qtree._ids) == 100, len(qtree._ids) for i in range(100, 10): for j in range(100, 10): assert qtree.find_intersect((i+1, j+1, 1, 1)) == ['%dx%d' % (i, j)], \ qtree.find_intersect((i+1, j+1, 1, 1))
def __init__(self, canvas=None): self._matrix = cairo.Matrix() self._painter = DefaultPainter(self) self._bounding_box_painter = BoundingBoxPainter(self) # Handling selections. # TODO: Move this to a context? self._selected_items = set() self._focused_item = None self._hovered_item = None self._dropzone_item = None self._qtree = Quadtree() self._bounds = Rectangle(0, 0, 0, 0) self._canvas = None if canvas: self._set_canvas(canvas)
def test_moving_items(self): qtree = Quadtree((0, 0, 100, 100), capacity=10) for i in range(0, 100, 10): for j in range(0, 100, 10): qtree.add("%dx%d" % (i, j), (i, j, 10, 10)) assert len(qtree._ids) == 100, len(qtree._ids) assert qtree._bucket._buckets, qtree._bucket._buckets for i in range(4): assert qtree._bucket._buckets[i]._buckets for j in range(4): assert not qtree._bucket._buckets[i]._buckets[j]._buckets # Check contents: # First sub-level contains 9 items. second level contains 4 items # ==> 4 * (9 + (4 * 4)) = 100 assert len(qtree._bucket.items) == 0, qtree._bucket.items for i in range(4): assert len(qtree._bucket._buckets[i].items) == 9 for item, bounds in qtree._bucket._buckets[i].items.iteritems(): assert qtree._bucket.find_bucket(bounds) is qtree._bucket._buckets[i] for j in range(4): assert len(qtree._bucket._buckets[i]._buckets[j].items) == 4 assert qtree.get_bounds('0x0') # Now move item '0x0' to the center of the first quadrant (20, 20) qtree.add('0x0', (20, 20, 10, 10)) assert len(qtree._bucket.items) == 0 assert len(qtree._bucket._buckets[0]._buckets[0].items) == 3, \ qtree._bucket._buckets[0]._buckets[0].items assert len(qtree._bucket._buckets[0].items) == 10, \ qtree._bucket._buckets[0].items # Now move item '0x0' to the second quadrant (70, 20) qtree.add('0x0', (70, 20, 10, 10)) assert len(qtree._bucket.items) == 0 assert len(qtree._bucket._buckets[0]._buckets[0].items) == 3, \ qtree._bucket._buckets[0]._buckets[0].items assert len(qtree._bucket._buckets[0].items) == 9, \ qtree._bucket._buckets[0].items assert len(qtree._bucket._buckets[1].items) == 10, \ qtree._bucket._buckets[1].items
def qtree(): qtree = Quadtree((0, 0, 100, 100)) for i in range(0, 100, 10): for j in range(0, 100, 10): qtree.add(item=f"{i:d}x{j:d}", bounds=Rectangle(i, j, 10, 10)) return qtree
def test_clipped_bounds(self): qtree = Quadtree((0, 0, 100, 100), capacity=10) qtree.add(1, (-100, -100, 120, 120)) self.assertEquals((0, 0, 20, 20), qtree.get_clipped_bounds(1))
def test_many_items_on_same_position(): capacity = 10 qtree: Quadtree[int, None] = Quadtree((0, 0, 0, 0), capacity=10) for i in range(0, capacity + 2): qtree.add(item=i, bounds=(0, 0, 10, 10), data=None)
def qtree(): qtree: Quadtree[str, None] = Quadtree((0, 0, 100, 100)) for i in range(0, 100, 10): for j in range(0, 100, 10): qtree.add(item=f"{i:d}x{j:d}", bounds=(i, j, 10, 10), data=None) return qtree
def qtree(): qtree = Quadtree((0, 0, 100, 100)) for i in range(0, 100, 10): for j in range(0, 100, 10): qtree.add(item="%dx%d" % (i, j), bounds=Rectangle(i, j, 10, 10)) return qtree