#!/usr/bin/env python3 # # Copyright 2008 Jose Fonseca # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # import operator import re import sys import gi gi.require_version("Gtk", "3.0") import xdot.ui from gi.repository import Gio, Gtk def __icon_button__(icon_name: str) -> Gtk.Button: icon = Gio.ThemedIcon(name=icon_name) image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON) button = Gtk.Button() button.add(image) return button class MyDotWindow(Gtk.Window): def __init__(self): super().__init__(title="Test") self.set_border_width(10) self.set_default_size(400, 200) self.dot = xdot.ui.DotWidget() hb = Gtk.HeaderBar() hb.set_show_close_button(True) self.set_titlebar(hb) box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) Gtk.StyleContext.add_class(box.get_style_context(), "linked") button = __icon_button__("zoom-in") button.connect("clicked", self.dot.on_zoom_in) box.add(button) button = __icon_button__("zoom-out") button.connect("clicked", self.dot.on_zoom_out) box.add(button) box.add(Gtk.SeparatorToolItem()) button = __icon_button__("zoom-fit-best") button.connect("clicked", self.dot.on_zoom_fit) box.add(button) button = __icon_button__("zoom-original") button.connect("clicked", self.dot.on_zoom_100) box.add(button) hb.pack_start(box) box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) Gtk.StyleContext.add_class(box.get_style_context(), "linked") self.search_entry = Gtk.Entry() self.search_entry.connect("activate", self.search) self.search_entry.connect("changed", self.search) self.search_entry.set_placeholder_text("Search...") box.add(self.search_entry) button = __icon_button__("find") button.connect("clicked", self.search) box.add(button) hb.pack_end(box) self.add(self.dot) self.set_focus(self.dot) def set_dotcode(self, code): self.dot.set_dotcode(code) def find_text(self, entry_text): found_items = [] dot_widget = self.dot try: regexp = re.compile(entry_text) except re.error as err: sys.stderr.write('warning: re.compile() failed with error "%s"\n' % err) return [] for element in ( dot_widget.graph.nodes + dot_widget.graph.edges + dot_widget.graph.shapes ): if element.search_text(regexp): found_items.append(element) return sorted(found_items, key=operator.methodcaller("get_text")) def search(self, _): txt = self.search_entry.get_text() if txt: items = self.find_text(txt) self.dot.set_highlight(items, search=True) else: self.dot.set_highlight(None, search=True) dotcode = b""" digraph G { Hello [URL="http://en.wikipedia.org/wiki/Hello"] World [URL="http://en.wikipedia.org/wiki/World"] Hello -> World } """ def main(): window = MyDotWindow() window.set_dotcode(dotcode) window.connect("delete-event", Gtk.main_quit) window.show_all() Gtk.main() if __name__ == "__main__": main()