1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
# Copyright (c) 2007 Hans Breuer <hans@breuer.org>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import dia
import math
def DeepCalc (dict, key, seen = None) :
# calculate all (deep) dependencies
# give a directory with component name as key and dependency components as list in dict[key][2]
if not seen :
seen = {}
for k in dict[key][2] :
if seen and seen.has_key (k) :
continue
seen[k] = 1
DeepCalc (dict, k, seen)
return len(seen.keys())
##
# \brief Callback function to be invoked by Dia's menu
#
# Implements a simple layout algorithm based on object connections
#
def arrange_connected (data, flags) :
objs = data.get_sorted_selected()
if len(objs) == 0 :
objs = data.active_layer.objects
# all objects having at least one connection
bs = {}
print "objs", len(objs)
edges = {}
for o in objs :
for c in o.connections: # ConnectionPoint
for n in c.connected: # connection object
if not (n.handles[0].connected_to and n.handles[1].connected_to):
continue
a = n.handles[0].connected_to.object
b = n.handles[1].connected_to.object
ak = a.properties["name"].value
bk = b.properties["name"].value
# create an edge key
ek = ak + "->" + bk
if edges.has_key (ek) :
continue # already seen
print ek
edges[ek] = 1
if bs.has_key (ak) :
use = bs[ak]
use[2].append (bk)
bs[ak] = use
else :
bs[ak] = [a, 0, [bk]]
if bs.has_key (bk) :
use = bs[bk]
use[1] += 1
bs[bk] = use
else :
bs[bk] = [b, 1, []]
# sort by number of connections
bst = []
dx = 0
dy = 0
for key in bs.keys() :
o = bs[key][0]
if not o.properties["elem_width"] :
print o
continue
if o.properties["elem_width"].value > dx : dx = o.properties["elem_width"].value
if o.properties["elem_height"].value > dy : dy = o.properties["elem_height"].value
n = bs[key][1] # (use count, dependencies)
bst.append ((o, n, DeepCalc (bs, key)))
bst.sort (lambda a, b : cmp(a[1], b[1]))
if len(bs) < 2 :
return
# average weight gives the number of rows
aw = 0.0
for t in bst :
aw += (t[1] + t[2])
aw = aw / len(bst)
rows = int (len(bst) / math.sqrt(aw))
if rows < 2 :
rows = 2
offsets = []
for i in range(0, rows) : offsets.append(0)
dx *= 1.4
dy *= 1.8
for t in bst :
y = t[1] # t[1] = 0 : start, noone uses it
# correction to move further down
c = rows - (rows * t[2] / aw)
if t[1] : # the less users the far below
if t[2] == 0 :
y = rows - 1
elif t[1] >= rows :
# compensate for some of the weight, FIXME: better guess needed
y = int(rows - 2 * aw / (t[2] + t[1]))
print t[0].properties["name"].value, t[1], t[2], y, c
# move the object to it's new place
x = offsets[y]
t[0].move (x * dx, y * dy)
offsets[y] += 1
data.update_extents ()
##
# \file arrange.py \brief Arrange Objects Plugin
#
# this module is loaded by some other plug-ins but can also work on it's own
# if it is loaded first as Dia plug-in and later as Python module everything works
# fine due to Pythoninitializing the module only once
#
# \ingroup PyDia
dia.register_callback ("Arrange Objects",
"<Display>/Objects/Arrange",
arrange_connected)
|