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()
def set_drawing_style(self): """Set the drawing style for the diagram based on the active style sheet.""" assert self.view assert self.diagram_css style = self.diagram.style(StyledDiagram(self.diagram, self.view)) bg = style.get("background-color") self.diagram_css.load_from_data( f"diagramview {{ background-color: rgba({int(255*bg[0])}, {int(255*bg[1])}, {int(255*bg[2])}, {bg[3]}) }}" .encode() if bg else "".encode()) sloppiness = style.get("line-style", 0.0) item_painter = ItemPainter() view = self.view if sloppiness: item_painter = FreeHandPainter(ItemPainter(), sloppiness=sloppiness) view.painter = (PainterChain().append(item_painter).append( HandlePainter()).append(FocusedItemPainter()).append( ToolPainter())) view.bounding_box_painter = BoundingBoxPainter(item_painter) view.queue_draw_refresh()
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")
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')