changeset 1128:b65ac686a7c5

Switch to the DOM-like API. The SPObject become the base of the DOM-like API.
author wycc
date Sat, 18 Dec 2010 09:00:55 +0800
parents baf4c4d48cff
children eca737d33a18 37a0f6ab2f91
files pyink/MBScene.py pyink/frameline.py pyink/mbtest.svg
diffstat 3 files changed, 560 insertions(+), 185 deletions(-) [+]
line wrap: on
line diff
--- a/pyink/MBScene.py	Tue Dec 14 11:04:56 2010 +0800
+++ b/pyink/MBScene.py	Sat Dec 18 09:00:55 2010 +0800
@@ -10,6 +10,7 @@
 import traceback
 import time
 import pybInkscape
+import math
 
 # Please refer to
 # http://www.assembla.com/wiki/show/MadButterfly/Inkscape_extention
@@ -55,6 +56,41 @@
 	self.type = typ
 	pass
     pass
+class DOM(pybInkscape.PYSPObject):
+    def __init__(self,obj=None):
+        self.proxy = obj
+	pass
+    def duplicate(self,doc):
+	return DOM(self.repr.duplicate(doc))
+
+class ObjectWatcher(pybInkscape.PYNodeObserver):
+    def __init__(self,obj,type,func,arg):
+        self.obj = obj
+	self.type = type
+	self.func = func
+	self.arg = arg
+
+    def notifyChildAdded(self,node,child,prev):
+        if self.type == 'DOMNodeInserted':
+	    self.func(node)
+    def notifyChildRemoved(self,node,child,prev):
+        if self.type == 'DOMNodeRemoved':
+	    self.func(node)
+    def notifyChildOrderChanged(self,node,child,prev):
+        pass
+    def notifyContentChanged(self,node,old_content,new_content):
+        print 'cont'
+        if self.type == 'DOMSubtreeModified':
+	    self.func(node)
+    def notifyAttributeChanged(self,node, name, old_value, new_value):
+        print 'attr'
+        if self.type == 'DOMAttrModified':
+	    self.func(node,name)
+
+def addEventListener(obj, type, func,arg):
+    obs = ObjectWatcher(obj,type,func,arg)
+    obj.addSubtreeObserver(obs)
+    
 
 _scenes = '{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scenes'
 _scene = '{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene'
@@ -93,7 +129,7 @@
 	self.scenemap = None
 	self.top = None
 	self.last_update = None
-	self.startPolling()
+	pybInkscape.inkscape.connect('change_selection', self.show_selection)
 	self.last_select = None
 	pass
 
@@ -118,6 +154,23 @@
 	    self.nameEditor.set_text('')
 	    pass
         glib.timeout_add(500,self.startPolling)
+    def show_selection(self,w,obj):
+	objs =  self.desktop.selection.list()
+	try:
+	    o = objs[0]
+	    print o.getCenter()
+	    if o == self.last_select: 
+	        return
+	except:
+	    self.nameEditor.set_text('')
+	    self.last_select = None
+	    return
+	self.last_select = o
+	try:
+	    self.nameEditor.set_text(o.repr.attribute("inkscape:label"))
+	except:
+	    self.nameEditor.set_text('')
+	    pass
 
     def confirm(self,msg):
 	vbox = gtk.VBox()
@@ -146,23 +199,23 @@
     def parseMetadata(self,node):
 	self.current = 1
 	for n in node.childList():
-	    if n.repr.name() == 'ns0:scenes':
+	    if n.name() == 'ns0:scenes':
 		self.scenemap={}
 		try:
-		    cur = int(n.repr.attribute("current"))
+		    cur = int(n.attribute("current"))
 		except:
 		    cur = 1
 		self.current = cur
 
 		for s in n.childList():
-		    if s.repr.name() == 'ns0:scene':
+		    if s.name() == 'ns0:scene':
 			try:
-			    start = int(s.repr.attribute("start"))
+			    start = int(s.attribute("start"))
 			except:
 			    traceback.print_exc()
 			    continue
 			try:
-			    end = s.repr.attribute("end")
+			    end = s.attribute("end")
 			    if end == None:
 				end = start
 				pass
@@ -170,13 +223,13 @@
 			    end = start
 			    pass
 			try:
-			    typ = s.repr.attribute('type')
+			    typ = s.attribute('type')
 			    if typ == None:
 				typ = 'normal'
 			except:
 			    traceback.print_exc()
 			    typ = 'normal'
-			link = s.repr.attribute("ref")
+			link = s.attribute("ref")
 			self.scenemap[link] = [int(start),int(end),typ]
 			if cur >= start and cur <= end:
 			    self.currentscene = link
@@ -187,19 +240,20 @@
 	    pass
 	pass
 	if self.scenemap==None:
-	    self.desktop.doc().root().repr.setAttribute("xmlns:ns0","http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd",True)
-	    scenes = self.desktop.doc().rdoc.createElement("ns0:scenes")
-	    node.repr.appendChild(scenes)
+	    #self.desktop.doc().root().repr.setAttribute("xmlns:ns0","http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd")
+	    self.dom.setAttribute("xmlns:ns0","http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd")
+	    scenes = self.document.createElement("ns0:scenes")
+	    node.appendChild(scenes)
     def update(self):
-        doc = self.desktop.doc().root()
-	rdoc = self.desktop.doc().rdoc
+        doc = self.dom
+	rdoc = self.document
 	for node in doc.childList():
-	    if node.repr.name() == 'svg:metadata':
+	    if node.name() == 'svg:metadata':
 	        for t in node.childList():
-		    if t.repr.name() == "ns0:scenes":
-		        node.repr.removeChild(t.repr)
+		    if t.name() == "ns0:scenes":
+		        node.removeChild(t)
 			ns = rdoc.createElement("ns0:scenes")
-			node.repr.appendChild(ns)
+			node.appendChild(ns)
 			for layer in range(0,len(self._framelines)):
 			    lobj = self._framelines[layer]
 			    lobj.addScenes(rdoc,ns)
@@ -213,24 +267,37 @@
 	"""
 	self.layers = []
 	self.scenemap = None
-	doc = self.desktop.doc().root()
+	doc = self.dom
 
         #obs = pybInkscape.PYNodeObserver()
-        obs = LayerAddRemoveWatcher(self)
-        doc.repr.addObserver(obs)
+        #obs = LayerAddRemoveWatcher(self)
+        #doc.addObserver(obs)
+	addEventListener(doc,'DOMNodeInserted',self.updateUI,None)
+	addEventListener(doc,'DOMNodeRemoved',self.updateUI,None)
+	doc.childList()
 	for node in doc.childList():
-	    if node.repr.name() == 'svg:metadata':
+	    print node.name()
+	    if node.name() == 'svg:metadata':
 		self.parseMetadata(node)
 		pass
-	    elif node.repr.name() == 'svg:g':
+	    elif node.name() == 'svg:g':
 		oldscene = None
-	        obs = LayerAttributeWatcher(self)
-	        node.repr.addObserver(obs)
+	        #obs = LayerAttributeWatcher(self)
+	        addEventListener(doc,'DOMAttrModified',self.updateUI,None)
+	        #node.addObserver(obs)
 		lyobj = Layer(node)
 		self.layers.append(lyobj)
 		lyobj.current_scene = []
 		for scene in node.childList():
-		    if scene.repr.name() == 'svg:g':
+		    print scene.getCenter()
+		    if scene.name() == 'svg:g':
+		        try:
+			    label = scene.attribute('inkscape:label')
+			    if label == 'dup':
+			        node.removeChild(scene)
+			except:
+			    pass
+
 			try:
 			    scmap = self.scenemap[scene.getId()]
 			    if scmap == None:
@@ -256,7 +323,7 @@
 
     def collectID(self):
 	self.ID = {}
-	root = self.desktop.doc().root()
+	root = self.dom
 	for n in root.childList():
 	    self.collectID_recursive(n)
 	    pass
@@ -302,20 +369,20 @@
 	"""
 	x = self.last_frame
 	y = self.last_line
-	rdoc = self.desktop.doc().rdoc
+	rdoc = self.document
 	ns = rdoc.createElement("svg:g")
 	txt = rdoc.createElement("svg:rect")
-	txt.setAttribute("x","0",True)
-	txt.setAttribute("y","0",True)
-	txt.setAttribute("width","100",True)
-	txt.setAttribute("height","100",True)
-	txt.setAttribute("style","fill:#ff00",True)
+	txt.setAttribute("x","0")
+	txt.setAttribute("y","0")
+	txt.setAttribute("width","100")
+	txt.setAttribute("height","100")
+	txt.setAttribute("style","fill:#ff00")
 	ns.appendChild(txt)
 	gid = self.last_line.node.label()+self.newID()
 	self.ID[gid]=1
-	ns.setAttribute("id",gid,True)
-	ns.setAttribute("inkscape:groupmode","layer",True)
-	self.last_line.node.repr.appendChild(ns)
+	ns.setAttribute("id",gid)
+	ns.setAttribute("inkscape:groupmode","layer")
+	self.last_line.node.appendChild(ns)
 	print 'Add key ', x
 	self.last_line.add_keyframe(x,ns)
 	self.update()
@@ -325,7 +392,7 @@
     def removeKeyScene(self):
 	nth = self.last_frame
 	y = self.last_line
-	rdoc = self.desktop.doc().rdoc
+	rdoc = self.document
 	i = 0
 	layer = self.last_line
 	while i < len(layer._keys):
@@ -427,6 +494,16 @@
 	    pass
 	pass
 
+    def updateMapping(self):
+	self.nodeToItem={}
+	root = self.dom
+	self.updateMappingNode(root)
+    def updateMappingNode(self,node):
+	for c in node.childList():
+	    self.updateMappingNode(c)
+	    self.nodeToItem[c.getId()] = c
+	    print "Add",c.getId()
+
     
     def setCurrentScene(self,nth):
 	"""
@@ -443,6 +520,7 @@
 	    available.
 	"""
 	self.current = nth
+	self.updateMapping()
 	for layer in self._framelines:
 	    i=0
 
@@ -463,23 +541,23 @@
 		print s.ref.attribute("id"),s.idx,s.left_tween,s.right_tween
 		if s.right_tween is False:
 		    if nth == s.idx+1:
-		        s.ref.setAttribute("style","",True)
+		        s.ref.setAttribute("style","")
 		    else:
-		        s.ref.setAttribute("style","display:none",True)
+		        s.ref.setAttribute("style","display:none")
 		    i = i + 1
 		    continue
 		if nth == s.idx + 1:
-		    s.ref.setAttribute("style","",True)
+		    s.ref.setAttribute("style","")
 		else:
 		    if nth > (s.idx+1) and nth <= (layer._keys[i+1].idx+1):
 			if i+2 < len(layer._keys):
-			    layer.duplicateGroup = self.desktop.doc().rdoc.createElement("svg:g")
-			    layer.duplicateGroup.setAttribute("inkscape:label","dup",True)
-			    s.ref.setAttribute("style","display:none",True)
+			    layer.duplicateGroup = self.document.createElement("svg:g")
+			    layer.duplicateGroup.setAttribute("inkscape:label","dup")
+			    s.ref.setAttribute("style","display:none")
 			    s.ref.parent().appendChild(layer.duplicateGroup)
 			    self.updateTweenContent(layer.duplicateGroup, layer.get_tween_type(s.idx),s, layer._keys[i+2], nth)
 		    else:
-		        s.ref.setAttribute("style","display:none",True)
+		        s.ref.setAttribute("style","display:none")
 		i = i + 2
 		pass
 	    pass
@@ -498,15 +576,16 @@
 	d = dest.ref.firstChild()
 	sources={}
 	dests={}
+	
 	# Collect all objects
 	while d:
 	    try:
 		label = d.attribute("inkscape:label")
 	    except:
-		d = d.next()
+		d = d.getNext()
 		continue
-	    dests[label.value()] = d
-	    d = d.next()
+	    dests[label] = d
+	    d = d.getNext()
 	# Check if the object in the source exists in the destination
 	s = source.ref.firstChild()
 	d = dest.ref.firstChild()
@@ -518,7 +597,7 @@
 		if label:
 		    if dests.hasattr(label.value()):
 			self.updateTweenObject(obj,typ,s,dests[label.value()],percent)
-			s = s.next()
+			s = s.getNext()
 			continue
 	    except:
 		pass
@@ -526,16 +605,16 @@
 	    while d:
 		try:
 		    d.attribute("inkscape:label")
-		    d = d.next()
+		    d = d.getNext()
 		    continue
 		except:
 		    pass
 		if s.name() == d.name():
 		    self.updateTweenObject(obj,typ,s,d,percent)
-		    d = d.next()
+		    d = d.getNext()
 		    break
-		d = d.next()
-	    s = s.next()
+		d = d.getNext()
+	    s = s.getNext()
     def parseTransform(self,obj):
 	"""
 	    Return the transform matrix of an object
@@ -561,7 +640,7 @@
 
     def invA(self,m):
         d = m[0]*m[3]-m[2]*m[1]
-	return [m[3]/d, m[1]/d, -m[2]/d, m[0]/d, (m[1]*m[5]-m[4]*m[3])/d, (m[4]*m[2]-m[0]*m[5])/d]
+	return [m[3]/d, -m[1]/d, -m[2]/d, m[0]/d, (m[1]*m[5]-m[4]*m[3])/d, (m[4]*m[2]-m[0]*m[5])/d]
     def mulA(self,a,b):
         return [a[0]*b[0]+a[1]*b[2],
 	        a[0]*b[1]+a[1]*b[3],
@@ -569,17 +648,51 @@
 		a[2]*b[1]+a[3]*b[3],
 		a[0]*b[4]+a[1]*b[5]+a[4],
 		a[2]*b[4]+a[3]*b[5]+a[5]]
+    def parseMatrix(self,m):
+        d = (1-m[0])*(1-m[3])-m[1]*m[2]
+	if d == 0:
+	    return [1,0,0,1,m[4],m[5]]
+	else:
+            return [m[0],m[1],m[2],m[3],(m[4]-m[3]*m[4]+m[1]*m[5])/d,(m[5]-m[0]*m[5]+m[2]*m[4])/d]
+
+    def decomposition(self,m):
+        if m[0]*m[3] == m[1]*m[2]:
+	    print "The affine matrix is singular"
+	    return [1,0,0,1,0,0]
+	A=m[0]
+	B=m[2]
+	C=m[1]
+	D=m[3]
+	E=m[4]
+	F=m[5]
+	sx = math.sqrt(m[0]*m[0]+m[2]*m[2])
+	A = A/sx
+	B = B/sx
+	shear = m[0]*m[1]+m[2]*m[3]
+	C = C - A*shear
+	D = D - B*shear
+	sy = math.sqrt(C*C+D*D)
+	C = C/sy
+	D = D/sy
+	r = A*D-B*C
+	if r == -1:
+	    shear = -shear
+	    sy = -sy
+	R = math.atan2(B,A)
+	return [sx,sy, R, E,F]
 
 	    
     def updateTweenObject(self,obj,typ,s,d,p):
 	"""
 	    Generate tweened object in the @obj by using s and d in the @p percent
+	    http://lists.w3.org/Archives/Public/www-style/2010Jun/0602.html
 	"""
 	print 'compare',s,d
 	if typ == 'relocate':
 	    print "percent",p
-	    newobj = s.duplicate(self.desktop.doc().rdoc)
-	    top = self.desktop.doc().rdoc.createElement("svg:g")
+	    newobj = s.duplicate(self.document)
+	    newobj.setAttribute("ref", s.getId())
+	    top = self.document.createElement("svg:g")
 	    top.appendChild(newobj)
 	    obj.appendChild(top)
 	    print s.name()
@@ -587,8 +700,7 @@
 		# Parse the translate or matrix
 		sm = self.parseTransform(s)
 		dm = self.parseTransform(d)
-		print "g", (dm[2]-sm[2])*p,(dm[5]-sm[5])*p
-		top.setAttribute("transform","translate(%g,%g)" % ((dm[2]-sm[2])*p,(dm[5]-sm[5])*p),True)
+		top.setAttribute("transform","translate(%g,%g)" % ((dm[2]-sm[2])*p,(dm[5]-sm[5])*p))
 	    else:
 		try:
 		    sx = float(s.attribute("x"))
@@ -598,32 +710,50 @@
 		    tx = (dx-sx)*p
 		    ty = (dy-sy)*p
 		    print tx,ty
-		    top.setAttribute("transform","translate(%g,%g)" % (tx,ty),True)
+		    top.setAttribute("transform","translate(%g,%g)" % (tx,ty))
 		except:
 		    #traceback.print_exc()
 		    pass
 	    pass
 	elif typ == 'scale':
-	    newobj = s.duplicate(self.desktop.doc().rdoc)
-	    top = self.desktop.doc().rdoc.createElement("svg:g")
+	    newobj = s.duplicate(self.document)
+	    top = self.document.createElement("svg:g")
 	    top.appendChild(newobj)
 	    obj.appendChild(top)
+	        
+	    print s,d
 	    if s.name() == 'svg:g':
 		# Parse the translate or matrix
+		# 
+		# D  = B inv(A)
+	        try:
+	            item = self.nodeToItem[s.attribute("id")]
+		    (ox,oy) = item.getCenter()
+	        except:
+		    ox = 0
+		    oy = 0
+	        try:
+	            item = self.nodeToItem[d.attribute("id")]
+		    (dx,dy) = item.getCenter()
+	        except:
+		    dx = 0
+		    dy = 0
+		    
 		sm = self.parseTransform(s)
+		ss = self.decomposition(sm)
 		dm = self.parseTransform(d)
-		# r(1)*A = B
-		#   ==> r(1) = B * inv(A)
-		r1 = self.mulA(dm,self.invA(sm))
-		t0 = 1+ (r1[0]-1)*p
-		t1 = r1[1]*p
-		t2 = r1[2]*p
-		t3 = 1+(r1[3]-1)*p
-		t4 = r1[4]*p
-		t5 = r1[5]*p
-
-		print "scale: %g %g %g %g %g %g" % (t0,t1,t2,t3,t4,t5)
-		top.setAttribute("transform","matrix(%g,%g,%g,%g,%g,%g)" % (t0,t1,t2,t3,t4,t5),True)
+		dd = self.decomposition(dm)
+		sx = ss[0]*(1-p)+dd[0]*p
+		sy = ss[1]*(1-p)+dd[1]*p
+		a  = ss[2]*(1-p)+dd[2]*p
+		tx = sx*(1-p)+dx*p
+		ty = sy*(1-p)+dy*p
+		#m = self.mulA([math.cos(a),-math.sin(a),math.sin(a),math.cos(a),0,0],[sx,0,0,sy,0,0])
+		m = [sx,0,0,sy,0,0]
+		m = self.mulA(m,[1,0,0,1,-ox,-oy])
+		m = [1,0,0,1,-ox,-oy]
+		if dd[0] != ss[0]:
+		    top.setAttribute("transform","matrix(%g,%g,%g,%g,%g,%g)" % (m[0],m[1],m[2],m[3],m[4],m[5]))
 	    else:
 		try:
 		    sw = float(s.attribute("width"))
@@ -633,7 +763,7 @@
 		    tx = (dw-sw)*p+sw
 		    ty = (dh-sh)*p+sh
 		    print tx,ty
-		    top.setAttribute("transform","matrix(%g,0,0,%g,0,0)" % (tx,ty),True)
+		    top.setAttribute("transform","matrix(%g,0,0,%g,0,0)" % (tx,ty))
 		except:
 		    traceback.print_exc()
 		    pass
@@ -759,9 +889,9 @@
 	    else:
 	        frameline.label.set_text(frameline.node.label())
 	    for scene in layer.scenes:
-		frameline.add_keyframe(scene.start-1,scene.node.repr)
+		frameline.add_keyframe(scene.start-1,scene.node)
 		if scene.start != scene.end:
-		    frameline.add_keyframe(scene.end-1,scene.node.repr)
+		    frameline.add_keyframe(scene.end-1,scene.node)
 		    frameline.tween(scene.start-1,scene.type)
 		pass
 	    pass
@@ -798,24 +928,24 @@
 	    i = i + 1
     def duplicateSceneGroup(self,gid):
 	# Search for the duplicated group
-        doc = self.desktop.doc().root()
-	rdoc = self.desktop.doc().rdoc
+        doc = self.dom
+	rdoc = self.document
 	orig = None
 	for node in doc.childList():
-	    if node.repr.name() == 'svg:g':
+	    if node.name() == 'svg:g':
 	        for t in node.childList():
-		    if t.repr.name() == "svg:g":
-			if t.repr.attribute("id") == gid:
-			    orig = t.repr
+		    if t.name() == "svg:g":
+			if t.attribute("id") == gid:
+			    orig = t
 			    break
 	if orig == None:
 	    return None
 	ns = orig.duplicate(rdoc)
 	gid = self.last_line.node.label()+self.newID()
 	self.ID[gid]=1
-	ns.setAttribute("id",gid,True)
-	ns.setAttribute("inkscape:groupmode","layer",True)
-	self.last_line.node.repr.appendChild(ns)
+	ns.setAttribute("id",gid)
+	ns.setAttribute("inkscape:groupmode","layer")
+	self.last_line.node.appendChild(ns)
 	return ns
     
     def doEditScene(self,w):
@@ -841,7 +971,7 @@
 	pass
     def changeObjectLabel(self,w):
 	o = self.desktop.selection.list()[0]
-	o.repr.setAttribute("inkscape:label", self.nameEditor.get_text(), True)
+	o.setAttribute("inkscape:label", self.nameEditor.get_text())
     def addNameEditor(self,hbox):
 	self.nameEditor = gtk.Entry(max=40)
 	hbox.pack_start(self.nameEditor,expand=False,fill=False)
@@ -923,12 +1053,14 @@
 	gtk.main_quit()
 	pass
 
-    def updateUI(self):
+    def updateUI(self,node=None,arg=None):
         if self.last_update!= None:
             glib.source_remove(self.last_update)
         self.last_update = glib.timeout_add(300,self.show)
     def show(self):
 	self.OK = True
+	self.dom = self.desktop.doc().root()
+	self.document = self.desktop.doc().rdoc
 	self.parseScene()
 	self._create_framelines()
 	self._update_framelines()
--- a/pyink/frameline.py	Tue Dec 14 11:04:56 2010 +0800
+++ b/pyink/frameline.py	Sat Dec 18 09:00:55 2010 +0800
@@ -666,7 +666,7 @@
 		    ss.setAttribute("type", "normal", True)
 		elif self._keys[i].right_tween_type == self._tween_type_move:
 		    ss.setAttribute("type", "relocate", True)
-		elif self._keys[i].right_tween_type == self._tween_type_scale:
+		elif self._keys[i].right_tween_type == self._tween_type_shape:
 		    ss.setAttribute("type", "scale", True)
 	    else:
 	        ss = rdoc.createElement("ns0:scene")
--- a/pyink/mbtest.svg	Tue Dec 14 11:04:56 2010 +0800
+++ b/pyink/mbtest.svg	Sat Dec 18 09:00:55 2010 +0800
@@ -27,9 +27,9 @@
      inkscape:pageopacity="0.0"
      inkscape:pageshadow="2"
      inkscape:zoom="1.6029106"
-     inkscape:cx="238.58561"
-     inkscape:cy="290.40921"
-     inkscape:current-layer="layer2"
+     inkscape:cx="304.10148"
+     inkscape:cy="340.31842"
+     inkscape:current-layer="Backgrounds7058"
      inkscape:document-units="px"
      showgrid="false"
      inkscape:window-width="1400"
@@ -219,6 +219,219 @@
        y1="28.009714"
        x2="104.68548"
        y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient3279"
+       gradientUnits="userSpaceOnUse"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5"
+       id="linearGradient3151"
+       gradientUnits="userSpaceOnUse"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714"
+       gradientTransform="scale(0,0)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient3153"
+       gradientUnits="userSpaceOnUse"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714"
+       gradientTransform="matrix(0.237454,0,0,0,30.388816,0)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient10701"
+       gradientUnits="userSpaceOnUse"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5"
+       id="linearGradient18053"
+       gradientUnits="userSpaceOnUse"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient19291"
+       gradientUnits="userSpaceOnUse"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient19296"
+       gradientUnits="userSpaceOnUse"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714"
+       gradientTransform="translate(75.331712,-0.46789912)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient19303"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(75.331712,-0.46789912)"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient20029"
+       gradientUnits="userSpaceOnUse"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient20034"
+       gradientUnits="userSpaceOnUse"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714"
+       gradientTransform="translate(75.331712,-0.46789912)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient20068"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(75.331712,-0.46789912)"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient3184"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(75.331712,-0.46789912)"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5"
+       id="linearGradient4893"
+       gradientUnits="userSpaceOnUse"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient4895"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(75.331712,-0.46789912)"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5"
+       id="linearGradient4897"
+       gradientUnits="userSpaceOnUse"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient4899"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(75.331712,-0.46789912)"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient4138"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(75.331712,-0.46789912)"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient5880"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(75.331712,-0.46789912)"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient3170"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(158.65467,189.3155)"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient3199"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(158.65467,189.3155)"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient3693"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(78.799936,12.76167)"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0-5-5"
+       id="linearGradient3700"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(78.799936,12.76167)"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
   </defs>
   <metadata
      id="metadata2388">
@@ -252,10 +465,10 @@
          start="1"
          ref="g3303"
          end="15"
-         type="relocate" />
+         type="scale" />
       <ns0:scene
          start="16"
-         ref="Backgrounds4326"
+         ref="Backgrounds7058"
          type="normal" />
     </ns0:scenes>
   </metadata>
@@ -266,11 +479,11 @@
      style="display:inline">
     <g
        style="display:none"
-       transform="translate(-15.128732,2.0275737)"
        id="g3303"
        inkscape:label="action1">
       <g
-         id="g3189">
+         id="g3189"
+         transform="translate(-0.898833,11.981842)">
         <rect
            style="fill:#00ffff;fill-opacity:1;stroke:#000000;stroke-opacity:1;display:inline"
            id="rect2437"
@@ -288,98 +501,12 @@
            rx="10"
            ry="10" />
       </g>
-      <rect
-         y="15.22048"
-         x="32.440987"
-         height="25.57847"
-         width="71.744492"
-         id="rect2439"
-         style="fill:url(#linearGradient3237);fill-opacity:1;stroke:none;filter:url(#filter3295-1-3)" />
-      <text
-         id="text3299"
-         y="33.312569"
-         x="39.927368"
-         style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
-         xml:space="preserve"><tspan
-           style="font-size:16px"
-           y="33.312569"
-           x="39.927368"
-           id="tspan3301"
-           sodipodi:role="line">Action</tspan></text>
       <g
-         style="display:inline"
-         id="g3308"
-         transform="translate(75.331712,-0.46789912)">
+         id="g18021"
+         transform="translate(-0.898833,11.981842)">
         <rect
-           y="15.22048"
-           x="32.440987"
-           height="25.57847"
-           width="71.744492"
-           id="rect3310"
-           style="fill:url(#linearGradient3316-4-8-2);fill-opacity:1;stroke:none;filter:url(#filter3295-1-3-2)" />
-        <text
-           id="text3312"
-           y="33.312569"
-           x="39.927368"
-           style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
-           xml:space="preserve"><tspan
-             style="font-size:16px"
-             y="33.312569"
-             x="39.927368"
-             id="tspan3314"
-             sodipodi:role="line">Select</tspan></text>
-      </g>
-    </g>
-    <g
-       inkscape:label="action1"
-       id="Backgrounds4326"
-       transform="translate(-15.128732,2.0275737)"
-       style=""
-       inkscape:groupmode="layer">
-      <g
-         id="g3889">
-        <rect
-           y="-10.98185"
-           x="0.93578684"
-           height="481.62387"
-           width="641.95721"
-           id="rect3891"
-           style="fill:#00ffff;fill-opacity:1;stroke:#000000;stroke-opacity:1;display:inline" />
-        <rect
-           ry="10"
-           rx="10"
-           y="5.8625031"
-           x="6.8625164"
-           height="46.789886"
-           width="624.48901"
-           id="rect3893"
-           style="fill:#ffcc1d;fill-opacity:1;stroke:none" />
-      </g>
-      <rect
-         style="fill:url(#linearGradient3237);fill-opacity:1;stroke:none;filter:url(#filter3295-1-3)"
-         id="rect3895"
-         width="71.744492"
-         height="25.57847"
-         x="32.440987"
-         y="15.22048" />
-      <text
-         xml:space="preserve"
-         style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
-         x="39.927368"
-         y="33.312569"
-         id="text3897"><tspan
-           sodipodi:role="line"
-           id="tspan3899"
-           x="39.927368"
-           y="33.312569"
-           style="font-size:16px">Action</tspan></text>
-      <g
-         transform="translate(170.78307,-0.46789912)"
-         id="g3901"
-         style="display:inline">
-        <rect
-           style="fill:url(#linearGradient3909);fill-opacity:1;stroke:none;filter:url(#filter3295-1-3-2)"
-           id="rect3903"
+           style="fill:url(#linearGradient4897);fill-opacity:1;stroke:none;filter:url(#filter3295-1-3)"
+           id="rect2439"
            width="71.744492"
            height="25.57847"
            x="32.440987"
@@ -389,13 +516,129 @@
            style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
            x="39.927368"
            y="33.312569"
-           id="text3905"><tspan
+           id="text3299"><tspan
              sodipodi:role="line"
-             id="tspan3907"
+             id="tspan3301"
              x="39.927368"
              y="33.312569"
+             style="font-size:16px">Action</tspan></text>
+      </g>
+      <g
+         id="g3165"
+         transform="translate(-80.478599,-177.80156)">
+        <rect
+           y="204.53598"
+           x="191.09566"
+           height="25.57847"
+           width="71.744492"
+           id="rect3310"
+           style="fill:url(#linearGradient3170);fill-opacity:1;stroke:none;filter:url(#filter3295-1-3-2)" />
+        <text
+           id="text3312"
+           y="222.62807"
+           x="198.58203"
+           style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+           xml:space="preserve"><tspan
+             style="font-size:16px"
+             y="222.62807"
+             x="198.58203"
+             id="tspan3314"
+             sodipodi:role="line">Select</tspan></text>
+      </g>
+      <g
+         id="g3361"
+         transform="translate(-0.898833,11.981842)">
+        <rect
+           transform="translate(15.128732,-2.0275737)"
+           y="14.596627"
+           x="180.92088"
+           height="29.321661"
+           width="67.377434"
+           id="rect3359"
+           style="fill:#000000;fill-opacity:1" />
+      </g>
+    </g>
+    <g
+       inkscape:label="action1"
+       id="Backgrounds7058"
+       style=""
+       inkscape:groupmode="layer">
+      <g
+         transform="translate(-0.898833,11.981842)"
+         id="g3173">
+        <rect
+           y="-10.98185"
+           x="0.93578684"
+           height="481.62387"
+           width="641.95721"
+           id="rect3175"
+           style="fill:#00ffff;fill-opacity:1;stroke:#000000;stroke-opacity:1;display:inline" />
+        <rect
+           ry="10"
+           rx="10"
+           y="5.8625031"
+           x="6.8625164"
+           height="46.789886"
+           width="624.48901"
+           id="rect3177"
+           style="fill:#ffcc1d;fill-opacity:1;stroke:none" />
+      </g>
+      <g
+         transform="translate(-0.898833,11.981842)"
+         id="g3179">
+        <rect
+           y="15.22048"
+           x="32.440987"
+           height="25.57847"
+           width="71.744492"
+           id="rect3181"
+           style="fill:url(#linearGradient4897);fill-opacity:1;stroke:none;filter:url(#filter3295-1-3)" />
+        <text
+           id="text3183"
+           y="33.312569"
+           x="39.927368"
+           style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+           xml:space="preserve"><tspan
+             style="font-size:16px"
+             y="33.312569"
+             x="39.927368"
+             id="tspan3185"
+             sodipodi:role="line">Action</tspan></text>
+      </g>
+      <g
+         id="g3695"
+         transform="matrix(1.3828119,0,0,2.7979599,-41.967781,-47.414913)">
+        <rect
+           style="fill:url(#linearGradient3700);fill-opacity:1;stroke:none;filter:url(#filter3295-1-3-2)"
+           id="rect3189"
+           width="71.744492"
+           height="25.57847"
+           x="111.24092"
+           y="27.982151" />
+        <text
+           xml:space="preserve"
+           style="font-size:24px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
+           x="118.72729"
+           y="46.074238"
+           id="text3191"><tspan
+             sodipodi:role="line"
+             id="tspan3193"
+             x="118.72729"
+             y="46.074238"
              style="font-size:16px">Select</tspan></text>
       </g>
+      <g
+         transform="translate(-0.898833,11.981842)"
+         id="g3195">
+        <rect
+           style="fill:#000000;fill-opacity:1"
+           id="rect3197"
+           width="67.377434"
+           height="29.321661"
+           x="180.92088"
+           y="14.596627"
+           transform="translate(15.128732,-2.0275737)" />
+      </g>
     </g>
   </g>
   <g