def SetTree(self, tree, filename): self.layout = CircleLayout(tree) self.layout.get_text_size = get_text_size self.layout.run() self.renderer.layout = self.layout self.filename = filename self.dirty = False self.show_bounding_circles = False self.auto_relayout = True self.scroll_x = 0 self.scroll_y = 0 self.zoom = 1.0 self.selected_node = None self.ReLayout()
canvas.pack() # Create one node rootNode = Node("root") rootNode.x = 300 rootNode.y = 200 rootNode.width = 50 rootNode.height = 50 rootNode.color = "black" graph.add(rootNode) for i in range(1, 10): toNode = Node(str(i)) toNode.x = random.randint(10, 500) toNode.y = random.randint(10, 300) toNode.color = "white" toNode.textColor = "red" graph.add(toNode) link = Link(rootNode, toNode, "Link-" + str(i)) link.color = 'green' graph.add(link) circleLayout = CircleLayout(120) circleLayout.doLayout(graph.nodes, rootNode) graph.render() win.mainloop()
class LayoutPanel(wx.Panel): def __init__(self, parent=None, ID=-1 ): wx.Panel.__init__(self, parent, size=(1,1), style=wx.WANTS_CHARS) self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseScroll) self.Bind(wx.EVT_MOTION, self.OnMouseMove) self.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp) self.Bind(wx.EVT_LEFT_DCLICK, self.OnMouseLeftDoubleClick) self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) self.Bind(wx.EVT_ERASE_BACKGROUND, lambda evt: None) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_SIZE, lambda e: self.Refresh()) self.drag_pos = None self.renderer = WxLayoutRenderer() self.editor = TreeEditor(self) def SetTree(self, tree, filename): self.layout = CircleLayout(tree) self.layout.get_text_size = get_text_size self.layout.run() self.renderer.layout = self.layout self.filename = filename self.dirty = False self.show_bounding_circles = False self.auto_relayout = True self.scroll_x = 0 self.scroll_y = 0 self.zoom = 1.0 self.selected_node = None self.ReLayout() def OnMouseScroll(self, evt): if evt.CmdDown(): r = 1.125**(evt.GetWheelRotation()/120.0) self.zoom *= r self.scroll_x *= r self.scroll_y *= r self.Refresh() def OnMouseMove(self, evt): if not evt.Dragging(): self.drag_pos = None else: self.CaptureMouse() if not self.drag_pos: self.drag_pos = evt.GetPosition() self.start_x,self.start_y = self.scroll_x,self.scroll_y else: displacement = evt.GetPosition() - self.drag_pos self.scroll_x = self.start_x + displacement.x self.scroll_y = self.start_y + displacement.y self.Refresh() self.ReleaseMouse() def OnMouseLeftUp(self, evt): if self.drag_pos is not None: self.drag_pos = None return x,y = evt.GetPositionTuple() x,y = self.renderer.screen_to_coord(x, y) n = self.layout.find_node(x,y) self.SelectNode(n) def OnMouseLeftDoubleClick(self, evt): self.OnMouseLeftUp(evt) self.OnEditNode(evt) def OnKeyDown(self, evt): if evt.CmdDown(): if evt.GetKeyCode() == wx.WXK_HOME: self.SelectNode(self.layout.root) elif evt.GetKeyCode() in [wx.WXK_LEFT, wx.WXK_RIGHT]: self.MoveNode(evt.GetKeyCode()) else: evt.Skip() return if evt.GetKeyCode() in [wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT]: self.MoveSelection(evt.GetKeyCode()) elif evt.GetKeyCode() == wx.WXK_F9: self.ReLayout() elif evt.GetKeyCode() == wx.WXK_BACK and self.selected_node is not None: self.selected_node = self.selected_node.parent self.ReLayout() elif evt.GetKeyCode() == ord('B'): self.show_bounding_circles = not self.show_bounding_circles self.Refresh() elif evt.GetKeyCode() == ord('P'): self.Pivot() elif evt.GetKeyCode() == ord('R'): self.SetRoot() else: evt.Skip() def OnPaint(self, evt): s = self.GetSize() dc = wx.MemoryDC() dc.SelectObject(wx.EmptyBitmap(s.x, s.y)) dc.SetBrush(wx.WHITE_BRUSH) dc.Clear() gc = wx.GraphicsContext.Create(dc) self.renderer.zoom = self.zoom self.renderer.scroll_x = self.scroll_x self.renderer.scroll_y = self.scroll_y self.renderer.selected_node = self.selected_node self.renderer.show_bounding = self.show_bounding_circles self.renderer.gc = gc self.renderer.dc = dc self.renderer.render() dc2 = wx.PaintDC(self) dc2.Blit(0,0,s.x,s.y,dc,0,0) del dc2 def MoveSelection(self, key_code): if self.selected_node is None: return node = self.selected_node all_neighbours = [] if node.parent is not None: all_neighbours.append(node.parent) all_neighbours.extend(node.children) if node.parent is not None: all_neighbours.extend([c for c in node.parent.children if c != node]) relevant_neighbours = [] x,y = self.layout.positions[node] for n in all_neighbours: nx,ny = self.layout.positions[n] dx = nx - x dy = ny - y if ((-dx > abs(dy) and key_code == wx.WXK_LEFT) or (dx > abs(dy) and key_code == wx.WXK_RIGHT) or (-dy > abs(dx) and key_code == wx.WXK_UP) or (dy > abs(dx) and key_code == wx.WXK_DOWN)): relevant_neighbours.append(n) if len(relevant_neighbours) > 0: new_node = relevant_neighbours[0] self.SelectNode(new_node) def SelectNode(self, node): if node != self.selected_node: self.selected_node = node self.Refresh() def Pivot(self): if self.selected_node is None or self.selected_node.parent is None: return mutation = tree_editor.PivotMutation(self.layout, self.selected_node) self.selected_node = mutation.parent self.editor.perform(mutation) self.dirty = True def SetRoot(self): if self.selected_node is None or self.selected_node.parent is None: return mutation = tree_editor.SetRootMutation(self.layout, self.selected_node) self.selected_node = mutation.old_root self.editor.perform(mutation) self.dirty = True def MoveNode(self, key_code): if self.selected_node is None or self.selected_node.parent is None: return if key_code == wx.WXK_LEFT and self.selected_node != self.selected_node.parent.children[0]: direction = -1 elif key_code == wx.WXK_RIGHT and self.selected_node != self.selected_node.parent.children[-1]: direction = 1 else: return mutation = tree_editor.MoveMutation(self.layout, self.selected_node, direction) self.editor.perform(mutation) self.dirty = True def OnZoomAll(self, evt): diameter = self.layout.root.bounding_radius*2 self.scroll_x,self.scroll_y = 0,0 self.zoom = min(self.renderer.width, self.renderer.height)/float(diameter) self.Refresh() def OnUndo(self, evt): self.editor.undo() def OnRedo(self, evt): self.editor.redo() def OnCopy(self, evt): if self.selected_node is None: return target = self.selected_node node_text = tree.to_string(target) clipdata = wx.TextDataObject() clipdata.SetText(node_text) wx.TheClipboard.Open() wx.TheClipboard.SetData(clipdata) wx.TheClipboard.Close() def OnCut(self, evt): if self.selected_node is None: return self.OnCopy(evt) self.OnDeleteNode(evt) def OnPaste(self, evt): target = self.selected_node if not target: target = self.layout.root if wx.TheClipboard.IsOpened(): return do = wx.TextDataObject() wx.TheClipboard.Open() success = wx.TheClipboard.GetData(do) wx.TheClipboard.Close() if not success: return node = tree.from_string(do.GetText()) mutation = tree_editor.InsertMutation(self.layout, target, node) self.editor.perform(mutation) self.dirty = True def OnDeleteNode(self, evt): if self.selected_node is not None and self.selected_node != self.layout.root: mutation = tree_editor.DeleteMutation(self.layout, self.selected_node) self.selected_node = None self.editor.perform(mutation) self.dirty = True def OnEditNode(self, evt): if self.selected_node is None: return #new_text = wx.GetTextFromUser("Edit node content", "Edit node", self.selected_node.content.replace('\n', ' ')) dlg = EditNodeDialog(self.selected_node.content, self.selected_node.properties, self.GetParent()) dlg.Show() val = dlg.ShowModal() new_text = dlg.GetNewContent() new_props = dlg.GetNewProperties() dlg.Destroy() if val != wx.ID_OK: return if len(new_text) == 0: return points = justify.get_points(new_text) all_js = justify.justify_text(points, 2) j = all_js[0][1] new_text = justify.render_text(new_text, j) mutation = tree_editor.EditMutation(self.layout, self.selected_node, new_text, new_props) self.editor.perform(mutation) self.dirty = True def OnAddNode(self, evt): if self.selected_node is None: return new_text = wx.GetTextFromUser("Enter new node content", "New node", '') if len(new_text) == 0: return points = justify.get_points(new_text) all_js = justify.justify_text(points, 2) j = all_js[0][1] new_text = justify.render_text(new_text, j) n = tree.Node(new_text) mutation = tree_editor.InsertMutation(self.layout, self.selected_node, n) self.editor.perform(mutation) self.dirty = True wx.PostEvent(self, evt) def ReLayout(self): self.layout.run() self.Refresh()