示例#1
0
    def set_drawing_style(self, sloppiness=0.0):
        """Set the drawing style for the diagram. 0.0 is straight,
        2.0 is very sloppy.  If the sloppiness is set to be anything
        greater than 0.0, the FreeHandPainter instances will be used
        for both the item painter and the box painter.  Otherwise, by
        default, the ItemPainter is used for the item and
        BoundingBoxPainter for the box."""

        view = self.view

        if sloppiness:

            item_painter = FreeHandPainter(ItemPainter(), sloppiness=sloppiness)
            box_painter = FreeHandPainter(BoundingBoxPainter(), sloppiness=sloppiness)

        else:

            item_painter = ItemPainter()
            box_painter = BoundingBoxPainter()

        view.painter = (
            PainterChain()
            .append(item_painter)
            .append(HandlePainter())
            .append(FocusedItemPainter())
            .append(ToolPainter())
        )

        view.bounding_box_painter = box_painter

        view.queue_draw_refresh()
示例#2
0
    def update_painters(self, view):
        sloppiness = self.properties.get("diagram.sloppiness", 0)

        if sloppiness:
            view.painter = FreeHandPainter(ItemPainter(), sloppiness)
            view.bounding_box_painter = FreeHandPainter(
                BoundingBoxPainter(), sloppiness
            )
        else:
            view.painter = ItemPainter()
示例#3
0
 def update_painters(self, view):
     
     self.logger.info('Updating painters')
     self.logger.debug('View is %s' % view)
     
     sloppiness = self.properties('diagram.sloppiness', 0)
     
     self.logger.debug('Sloppiness is %s' % sloppiness)
     
     if sloppiness:
         view.painter = FreeHandPainter(ItemPainter(), sloppiness)
         view.bounding_box_painter = FreeHandPainter(BoundingBoxPainter(), sloppiness)
     else:
         view.painter = ItemPainter()
示例#4
0
    def update_painters(self, view):

        logger.info("Updating painters")
        logger.debug("View is %s" % view)

        sloppiness = self.properties("diagram.sloppiness", 0)

        logger.debug("Sloppiness is %s" % sloppiness)

        if sloppiness:
            view.painter = FreeHandPainter(ItemPainter(), sloppiness)
            view.bounding_box_painter = FreeHandPainter(
                BoundingBoxPainter(), sloppiness)
        else:
            view.painter = ItemPainter()
示例#5
0
def apply_painters(view):
    painter = FreeHandPainter(ItemPainter(view.selection))
    view.painter = (PainterChain().append(painter).append(
        HandlePainter(view)).append(LineSegmentPainter(view.selection)).append(
            GuidePainter(view)).append(
                RubberbandPainter(rubberband_state(view))))
    view.bounding_box_painter = painter
示例#6
0
    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)
示例#7
0
    def on_write_demo_svg_clicked(button):
        assert view.model
        painter = ItemPainter()

        # Update bounding boxes with a temporaly CairoContext
        # (used for stuff like calculating font metrics)
        tmpsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0)
        tmpcr = cairo.Context(tmpsurface)
        bounding_box = BoundingBoxPainter(painter).bounding_box(
            canvas.get_all_items(), tmpcr)
        tmpcr.show_page()
        tmpsurface.flush()

        surface = cairo.SVGSurface("demo.svg", int(bounding_box.width),
                                   int(bounding_box.height))
        cr = cairo.Context(surface)
        cr.translate(-bounding_box.x, -bounding_box.y)
        painter.paint(items=list(view.model.get_all_items()), cairo=cr)
        cr.show_page()
        surface.flush()
        surface.finish()
示例#8
0
文件: view.py 项目: wglu2010/gaphas
    def __init__(self, canvas=None):
        self._matrix = cairo.Matrix()
        self._painter = DefaultPainter(self)
        self._bounding_box_painter = BoundingBoxPainter(ItemPainter(self), 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)
示例#9
0
    def on_clicked(button):
        svgview = View(view.canvas)
        svgview.painter = ItemPainter()

        # Update bounding boxes with a temporaly CairoContext
        # (used for stuff like calculating font metrics)
        tmpsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0)
        tmpcr = cairo.Context(tmpsurface)
        svgview.update_bounding_box(tmpcr)
        tmpcr.show_page()
        tmpsurface.flush()

        w, h = svgview.bounding_box.width, svgview.bounding_box.height
        surface = cairo.SVGSurface("demo.svg", w, h)
        cr = cairo.Context(surface)
        svgview.matrix.translate(-svgview.bounding_box.x, -svgview.bounding_box.y)
        svgview.paint(cr)
        cr.show_page()
        surface.flush()
        surface.finish()
示例#10
0
def create_window(canvas, title, zoom=1.0):
    view = GtkView()
    view.painter = (
        PainterChain()
        .append(FreeHandPainter(ItemPainter()))
        .append(HandlePainter())
        .append(FocusedItemPainter())
        .append(ToolPainter())
    )
    view.bounding_box_painter = FreeHandPainter(BoundingBoxPainter(ItemPainter()))
    w = Gtk.Window()
    w.set_title(title)
    w.set_default_size(400, 120)
    h = Gtk.HBox()
    w.add(h)

    # VBox contains buttons that can be used to manipulate the canvas:
    v = Gtk.VBox()
    v.set_property("border-width", 3)
    v.set_property("spacing", 2)
    f = Gtk.Frame()
    f.set_property("border-width", 1)
    f.add(v)
    h.pack_start(f, False, True, 0)

    v.add(Gtk.Label.new("Item placement:"))

    b = Gtk.Button.new_with_label("Add box")

    def on_clicked(button, view):
        # view.window.set_cursor(Gdk.Cursor.new(Gdk.CursorType.CROSSHAIR))
        view.tool.grab(PlacementTool(view, factory(view, MyBox), HandleTool(), 2))

    b.connect("clicked", on_clicked, view)
    v.add(b)

    b = Gtk.Button.new_with_label("Add line")

    def on_clicked(button):
        view.tool.grab(PlacementTool(view, factory(view, MyLine), HandleTool(), 1))

    b.connect("clicked", on_clicked)
    v.add(b)

    v.add(Gtk.Label.new("Zooming:"))

    b = Gtk.Button.new_with_label("Zoom in")

    def on_clicked(button):
        view.zoom(1.2)

    b.connect("clicked", on_clicked)
    v.add(b)

    b = Gtk.Button.new_with_label("Zoom out")

    def on_clicked(button):
        view.zoom(1 / 1.2)

    b.connect("clicked", on_clicked)
    v.add(b)

    v.add(Gtk.Label.new("Misc:"))

    b = Gtk.Button.new_with_label("Split line")

    def on_clicked(button):
        if isinstance(view.focused_item, Line):
            segment = Segment(view.focused_item, view)
            segment.split_segment(0)
            view.queue_draw_item(view.focused_item)

    b.connect("clicked", on_clicked)
    v.add(b)

    b = Gtk.Button.new_with_label("Delete focused")

    def on_clicked(button):
        if view.focused_item:
            canvas.remove(view.focused_item)

    b.connect("clicked", on_clicked)
    v.add(b)

    v.add(Gtk.Label.new("State:"))
    b = Gtk.ToggleButton.new_with_label("Record")

    def on_toggled(button):
        global undo_list
        if button.get_active():
            print("start recording")
            del undo_list[:]
            state.subscribers.add(undo_handler)
        else:
            print("stop recording")
            state.subscribers.remove(undo_handler)

    b.connect("toggled", on_toggled)
    v.add(b)

    b = Gtk.Button.new_with_label("Play back")

    def on_clicked(self):
        global undo_list
        apply_me = list(undo_list)
        del undo_list[:]
        print("Actions on the undo stack:", len(apply_me))
        apply_me.reverse()
        saveapply = state.saveapply
        for event in apply_me:
            print("Undo: invoking", event)
            saveapply(*event)
            print("New undo stack size:", len(undo_list))
            # Visualize each event:
            # while Gtk.events_pending():
            #    Gtk.main_iteration()

    b.connect("clicked", on_clicked)
    v.add(b)

    v.add(Gtk.Label.new("Export:"))

    b = Gtk.Button.new_with_label("Write demo.png")

    def on_clicked(button):
        svgview = View(view.canvas)
        svgview.painter = ItemPainter()

        # Update bounding boxes with a temporary CairoContext
        # (used for stuff like calculating font metrics)
        tmpsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0)
        tmpcr = cairo.Context(tmpsurface)
        svgview.update_bounding_box(tmpcr)
        tmpcr.show_page()
        tmpsurface.flush()

        w, h = svgview.bounding_box.width, svgview.bounding_box.height
        surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(w), int(h))
        cr = cairo.Context(surface)
        svgview.matrix.translate(-svgview.bounding_box.x, -svgview.bounding_box.y)
        cr.save()
        svgview.paint(cr)

        cr.restore()
        cr.show_page()
        surface.write_to_png("demo.png")

    b.connect("clicked", on_clicked)
    v.add(b)

    b = Gtk.Button.new_with_label("Write demo.svg")

    def on_clicked(button):
        svgview = View(view.canvas)
        svgview.painter = ItemPainter()

        # Update bounding boxes with a temporaly CairoContext
        # (used for stuff like calculating font metrics)
        tmpsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0)
        tmpcr = cairo.Context(tmpsurface)
        svgview.update_bounding_box(tmpcr)
        tmpcr.show_page()
        tmpsurface.flush()

        w, h = svgview.bounding_box.width, svgview.bounding_box.height
        surface = cairo.SVGSurface("demo.svg", w, h)
        cr = cairo.Context(surface)
        svgview.matrix.translate(-svgview.bounding_box.x, -svgview.bounding_box.y)
        svgview.paint(cr)
        cr.show_page()
        surface.flush()
        surface.finish()

    b.connect("clicked", on_clicked)
    v.add(b)

    b = Gtk.Button.new_with_label("Dump QTree")

    def on_clicked(button, li):
        view._qtree.dump()

    b.connect("clicked", on_clicked, [0])
    v.add(b)

    b = Gtk.Button.new_with_label("Pickle (save)")

    def on_clicked(button, li):
        f = open("demo.pickled", "wb")
        try:
            import pickle

            pickle.dump(view.canvas, f)
        finally:
            f.close()

    b.connect("clicked", on_clicked, [0])
    v.add(b)

    b = Gtk.Button.new_with_label("Unpickle (load)")

    def on_clicked(button, li):
        f = open("demo.pickled", "rb")
        try:
            import pickle

            canvas = pickle.load(f)
            canvas.update_now()
        finally:
            f.close()
        create_window(canvas, "Unpickled diagram")

    b.connect("clicked", on_clicked, [0])
    v.add(b)

    b = Gtk.Button.new_with_label("Unpickle (in place)")

    def on_clicked(button, li):
        f = open("demo.pickled", "rb")
        try:
            import pickle

            canvas = pickle.load(f)
        finally:
            f.close()
        # [i.request_update() for i in canvas.get_all_items()]
        canvas.update_now()
        view.canvas = canvas

    b.connect("clicked", on_clicked, [0])
    v.add(b)

    b = Gtk.Button.new_with_label("Reattach (in place)")

    def on_clicked(button, li):
        view.canvas = None
        view.canvas = canvas

    b.connect("clicked", on_clicked, [0])
    v.add(b)

    # Add the actual View:

    view.canvas = canvas
    view.zoom(zoom)
    view.set_size_request(150, 120)
    s = Gtk.ScrolledWindow.new()
    s.set_hexpand(True)
    s.add(view)
    h.add(s)

    w.show_all()

    w.connect("destroy", Gtk.main_quit)

    def handle_changed(view, item, what):
        print(what, "changed: ", item)

    view.connect("focus-changed", handle_changed, "focus")
    view.connect("hover-changed", handle_changed, "hover")
    view.connect("selection-changed", handle_changed, "selection")
示例#11
0
            message('skipping %s' % pname)
            continue

        if options.dir:
            odir = '%s/%s' % (options.dir, odir)

        outfilename = '%s/%s.%s' % (odir, dname, options.format)

        if not os.path.exists(odir):
            message('creating dir %s' % odir)
            os.makedirs(odir)

        message('rendering: %s -> %s...' % (pname, outfilename))

        view = View(diagram.canvas)
        view.painter = ItemPainter()

        tmpsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0)
        tmpcr = cairo.Context(tmpsurface)
        view.update_bounding_box(tmpcr)
        tmpcr.show_page()
        tmpsurface.flush()

        w, h = view.bounding_box.width, view.bounding_box.height
        if options.format == 'pdf':
            surface = cairo.PDFSurface(outfilename, w, h)
        elif options.format == 'svg':
            surface = cairo.SVGSurface(outfilename, w, h)
        elif options.format == 'png':
            surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(w + 1),
                                         int(h + 1))
示例#12
0
def main(argv=sys.argv[1:]):
    def message(msg):
        """
        Print message if user set verbose mode.
        """
        if options.verbose:
            print(msg, file=sys.stderr)

    usage = "usage: %prog [options] file1 file2..."

    parser = optparse.OptionParser(usage=usage)

    parser.add_option("-v",
                      "--verbose",
                      dest="verbose",
                      action="store_true",
                      help="verbose output")
    parser.add_option(
        "-u",
        "--use-underscores",
        dest="underscores",
        action="store_true",
        help="use underscores instead of spaces for output filenames",
    )
    parser.add_option("-d",
                      "--dir",
                      dest="dir",
                      metavar="directory",
                      help="output to directory")
    parser.add_option(
        "-f",
        "--format",
        dest="format",
        metavar="format",
        help="output file format, default pdf",
        default="pdf",
        choices=["pdf", "svg", "png"],
    )
    parser.add_option(
        "-r",
        "--regex",
        dest="regex",
        metavar="regex",
        help="process diagrams which name matches given regular expresion;"
        " name includes package name; regular expressions are case insensitive",
    )

    (options, args) = parser.parse_args(argv)

    if not args:
        parser.print_help()

    session = Session(
        services=["event_manager", "component_registry", "element_factory"])
    factory = session.get_service("element_factory")

    name_re = None
    if options.regex:
        name_re = re.compile(options.regex, re.I)

    # we should have some gaphor files to be processed at this point
    for model in args:
        message(f"loading model {model}")
        storage.load(model, factory)
        message("ready for rendering")

        for diagram in factory.select(lambda e: e.isKindOf(UML.Diagram)):
            odir = pkg2dir(diagram.package)

            # just diagram name
            dname = diagram.name
            # full diagram name including package path
            pname = f"{odir}/{dname}"

            if options.underscores:
                odir = odir.replace(" ", "_")
                dname = dname.replace(" ", "_")

            if name_re and not name_re.search(pname):
                message(f"skipping {pname}")
                continue

            if options.dir:
                odir = f"{options.dir}/{odir}"

            outfilename = f"{odir}/{dname}.{options.format}"

            if not os.path.exists(odir):
                message(f"creating dir {odir}")
                os.makedirs(odir)

            message(f"rendering: {pname} -> {outfilename}...")

            view = View(diagram.canvas)
            view.painter = ItemPainter()

            tmpsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0)
            tmpcr = cairo.Context(tmpsurface)
            view.update_bounding_box(tmpcr)
            tmpcr.show_page()
            tmpsurface.flush()

            w, h = view.bounding_box.width, view.bounding_box.height
            if options.format == "pdf":
                surface = cairo.PDFSurface(outfilename, w, h)
            elif options.format == "svg":
                surface = cairo.SVGSurface(outfilename, w, h)
            elif options.format == "png":
                surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(w + 1),
                                             int(h + 1))
            else:
                assert False, f"unknown format {options.format}"
            cr = cairo.Context(surface)
            view.matrix.translate(-view.bounding_box.x, -view.bounding_box.y)
            paint(view, cr)
            cr.show_page()

            if options.format == "png":
                surface.write_to_png(outfilename)

            surface.flush()
            surface.finish()
示例#13
0
def create_window(canvas, title, zoom=1.0):
    view = GtkView()
    view.painter = PainterChain(). \
        append(FreeHandPainter(ItemPainter())). \
        append(HandlePainter()). \
        append(FocusedItemPainter()). \
        append(ToolPainter())
    view.bounding_box_painter = FreeHandPainter(BoundingBoxPainter())
    w = gtk.Window()
    w.set_title(title)
    h = gtk.HBox()
    w.add(h)

    # VBox contains buttons that can be used to manipulate the canvas:
    v = gtk.VBox()
    v.set_property('border-width', 3)
    v.set_property('spacing', 2)
    f = gtk.Frame()
    f.set_property('border-width', 1)
    f.add(v)
    h.pack_start(f, expand=False)

    v.add(gtk.Label('Item placement:'))

    b = gtk.Button('Add box')

    def on_clicked(button, view):
        #view.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.CROSSHAIR))
        view.tool.grab(
            PlacementTool(view, factory(view, MyBox), HandleTool(), 2))

    b.connect('clicked', on_clicked, view)
    v.add(b)

    b = gtk.Button('Add line')

    def on_clicked(button):
        view.tool.grab(
            PlacementTool(view, factory(view, MyLine), HandleTool(), 1))

    b.connect('clicked', on_clicked)
    v.add(b)

    v.add(gtk.Label('Zooming:'))

    b = gtk.Button('Zoom in')

    def on_clicked(button):
        view.zoom(1.2)

    b.connect('clicked', on_clicked)
    v.add(b)

    b = gtk.Button('Zoom out')

    def on_clicked(button):
        view.zoom(1 / 1.2)

    b.connect('clicked', on_clicked)
    v.add(b)

    v.add(gtk.Label('Misc:'))

    b = gtk.Button('Split line')

    def on_clicked(button):
        if isinstance(view.focused_item, Line):
            segment = Segment(view.focused_item, view)
            segment.split_segment(0)
            view.queue_draw_item(view.focused_item)

    b.connect('clicked', on_clicked)
    v.add(b)

    b = gtk.Button('Delete focused')

    def on_clicked(button):
        if view.focused_item:
            canvas.remove(view.focused_item)
            #print 'items:', canvas.get_all_items()

    b.connect('clicked', on_clicked)
    v.add(b)

    v.add(gtk.Label('State:'))
    b = gtk.ToggleButton('Record')

    def on_toggled(button):
        global undo_list
        if button.get_active():
            print 'start recording'
            del undo_list[:]
            state.subscribers.add(undo_handler)
        else:
            print 'stop recording'
            state.subscribers.remove(undo_handler)

    b.connect('toggled', on_toggled)
    v.add(b)

    b = gtk.Button('Play back')

    def on_clicked(self):
        global undo_list
        apply_me = list(undo_list)
        del undo_list[:]
        print 'Actions on the undo stack:', len(apply_me)
        apply_me.reverse()
        saveapply = state.saveapply
        for event in apply_me:
            print 'Undo: invoking', event
            saveapply(*event)
            print 'New undo stack size:', len(undo_list)
            # Visualize each event:
            #while gtk.events_pending():
            #    gtk.main_iteration()

    b.connect('clicked', on_clicked)
    v.add(b)

    v.add(gtk.Label('Export:'))

    b = gtk.Button('Write demo.png')

    def on_clicked(button):
        svgview = View(view.canvas)
        svgview.painter = ItemPainter()

        # Update bounding boxes with a temporaly CairoContext
        # (used for stuff like calculating font metrics)
        tmpsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0)
        tmpcr = cairo.Context(tmpsurface)
        svgview.update_bounding_box(tmpcr)
        tmpcr.show_page()
        tmpsurface.flush()

        w, h = svgview.bounding_box.width, svgview.bounding_box.height
        surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(w), int(h))
        cr = cairo.Context(surface)
        svgview.matrix.translate(-svgview.bounding_box.x,
                                 -svgview.bounding_box.y)
        cr.save()
        svgview.paint(cr)

        cr.restore()
        cr.show_page()
        surface.write_to_png('demo.png')

    b.connect('clicked', on_clicked)
    v.add(b)

    b = gtk.Button('Write demo.svg')

    def on_clicked(button):
        svgview = View(view.canvas)
        svgview.painter = ItemPainter()

        # Update bounding boxes with a temporaly CairoContext
        # (used for stuff like calculating font metrics)
        tmpsurface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 0, 0)
        tmpcr = cairo.Context(tmpsurface)
        svgview.update_bounding_box(tmpcr)
        tmpcr.show_page()
        tmpsurface.flush()

        w, h = svgview.bounding_box.width, svgview.bounding_box.height
        surface = cairo.SVGSurface('demo.svg', w, h)
        cr = cairo.Context(surface)
        svgview.matrix.translate(-svgview.bounding_box.x,
                                 -svgview.bounding_box.y)
        svgview.paint(cr)
        cr.show_page()
        surface.flush()
        surface.finish()

    b.connect('clicked', on_clicked)
    v.add(b)

    b = gtk.Button('Dump QTree')

    def on_clicked(button, li):
        view._qtree.dump()

    b.connect('clicked', on_clicked, [0])
    v.add(b)

    b = gtk.Button('Pickle (save)')

    def on_clicked(button, li):
        f = open('demo.pickled', 'w')
        try:
            import cPickle as pickle
            pickle.dump(view.canvas, f)
        finally:
            f.close()

    b.connect('clicked', on_clicked, [0])
    v.add(b)

    b = gtk.Button('Unpickle (load)')

    def on_clicked(button, li):
        f = open('demo.pickled', 'r')
        try:
            import cPickle as pickle
            canvas = pickle.load(f)
            canvas.update_now()
        finally:
            f.close()
        create_window(canvas, 'Unpickled diagram')

    b.connect('clicked', on_clicked, [0])
    v.add(b)

    b = gtk.Button('Unpickle (in place)')

    def on_clicked(button, li):
        f = open('demo.pickled', 'r')
        try:
            import cPickle as pickle
            canvas = pickle.load(f)
        finally:
            f.close()
        #[i.request_update() for i in canvas.get_all_items()]
        canvas.update_now()
        view.canvas = canvas

    b.connect('clicked', on_clicked, [0])
    v.add(b)

    b = gtk.Button('Reattach (in place)')

    def on_clicked(button, li):
        view.canvas = None
        view.canvas = canvas

    b.connect('clicked', on_clicked, [0])
    v.add(b)

    # Add the actual View:

    view.canvas = canvas
    view.zoom(zoom)
    view.set_size_request(150, 120)
    s = gtk.ScrolledWindow()
    s.add(view)
    h.add(s)

    w.show_all()

    w.connect('destroy', gtk.main_quit)

    def handle_changed(view, item, what):
        print what, 'changed: ', item

    view.connect('focus-changed', handle_changed, 'focus')
    view.connect('hover-changed', handle_changed, 'hover')
    view.connect('selection-changed', handle_changed, 'selection')