changeset 941:9ba94c577a6f

Add scene editor. This vewrsion can only switch scene. It can not change the scene yet.
author wycc
date Sun, 14 Nov 2010 23:09:02 +0800
parents 5dedeedf0408
children a3f2fbf79191
files pyink/MBScene.py pyink/active-empty.png pyink/active-fill.png pyink/active-start.png pyink/empty.png pyink/fill.png pyink/mbtest.svg pyink/pyink.py pyink/start.png
diffstat 9 files changed, 877 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pyink/MBScene.py	Sun Nov 14 23:09:02 2010 +0800
@@ -0,0 +1,530 @@
+#!/usr/bin/python
+import pygtk
+import gtk
+from copy import deepcopy
+from lxml import etree
+import random
+import traceback
+
+# Please refer to http://www.assembla.com/wiki/show/MadButterfly/Inkscape_extention for the designed document.
+
+
+# Algorithm:
+# 
+# We will parse the first two level of the SVG DOM. collect a table of layer and scene.
+# 1. Collect the layer table which will be displayed as the first column of the grid.
+# 2. Get the maximum scene number. This will decide the size of the grid. 
+# 3. When F6 is pressed, we will check if this scene has been defined. This can be done by scan all second level group and check if the current scene number is within the 
+#    range specified by scene field. The function IsSceneDefined(scene) can be used for this purpose.
+# 4. If this is a new scene, we will append a new group which duplication the content of the last scene in the same group. The scene field will contain the number from the 
+#    last scene number of the last scene to the current scenen number. For example, if the last scene is from 4-7 and the new scene is 10, we will set the scene field as
+#    "8-10".
+# 5. If this scene are filled screne, we will split the existing scene into two scenes with the same content.
+
+class Layer:
+	def __init__(self,node):
+		self.scene = []
+		self.node = node
+		self.nodes=[]
+class Scene:
+	def __init__(self, node, start,end):
+		self.node = node
+		self.start = int(start)
+		self.end = int(end)
+
+
+class MBScene():
+	def __init__(self,desktop,win):
+		self.desktop = desktop
+		self.window = win
+		self.layer = []
+		self.layer.append(Layer(None))
+		self.scenemap = None
+
+	def confirm(self,msg):
+		vbox = gtk.VBox()
+		vbox.pack_start(gtk.Label(msg))
+		self.button = gtk.Button('OK')
+		vbox.pack_start(self.button)
+		self.button.connect("clicked", self.onQuit)
+		self.window.add(vbox)
+	def dumpattr(self,n):
+		s = ""
+		for a,v in n.attrib.items():
+			s = s + ("%s=%s"  % (a,v))
+		return s
+			
+	def dump(self,node,l=0):
+		print " " * l*2,"<", node.tag, self.dumpattr(node),">"
+		for n in node:
+			self.dump(n,l+1)
+		print " " * l * 2,"/>"
+	def parseMetadata(self,node):
+		self.current = 1
+		for n in node.childList():
+			if n.repr.name() == 'ns0:scenes':
+				self.scenemap={}
+				cur = int(n.repr.attribute("current"))
+				self.current = cur
+
+				for s in n.childList():
+					print '--->',s.repr.name()
+					if s.repr.name() == 'ns0:scene':
+						try:
+							start = int(s.repr.attribute("start"))
+						except:
+							traceback.print_exc()
+							continue
+						try:
+							end = s.repr.attribute("end")
+							if end == None:
+								end = start
+						except:
+							end = start
+						link = s.repr.attribute("ref")
+						self.scenemap[link] = [int(start),int(end)]
+						print "scene %d to %d" % (self.scenemap[link][0],self.scenemap[link][1])
+						if cur >= start and cur <= end:
+							self.currentscene = link
+
+					pass
+				pass
+			pass
+		pass
+						
+						
+	def parseScene(self):
+		"""
+		In this function, we will collect all items for the current scene and then relocate them back to the appropriate scene object.
+		"""
+		self.layer = []
+		self.scenemap = None
+		doc = self.desktop.doc().root()
+
+		for node in doc.childList():
+			if node.repr.name() == 'svg:metadata':
+				self.parseMetadata(node)
+			elif node.repr.name() == 'svg:g':
+				oldscene = None
+				#print layer.attrib.get("id")
+				lyobj = Layer(node)
+				self.layer.append(lyobj)
+				lyobj.current_scene = []
+				for scene in node.childList():
+					if scene.repr.name() == 'svg:g':
+						try:
+							scmap = self.scenemap[scene.getId()]
+							if scmap == None:
+								lyobj.current_scene.append(scene)
+								continue
+							if self.current <= scmap[1] and self.current >= scmap[0]:
+								oldscene = scene
+						except:
+							lyobj.current_scene.append(scene)
+							continue
+
+						lyobj.scene.append(Scene(scene,scmap[0],scmap[1]))
+					else:
+						lyobj.current_scene.append(scene)
+				pass
+
+				if oldscene != None:
+					# Put the objects back to the current scene
+					#for o in lyobj.current_scene:
+						#print o.tag
+						#oldscene.append(o)
+					pass
+				pass
+		pass
+
+		self.collectID()
+		self.dumpID()
+	def collectID(self):
+		self.ID = {}
+		root = self.desktop.doc().root()
+		for n in root.childList():
+			self.collectID_recursive(n)
+	def collectID_recursive(self,node):
+		self.ID[node.getId()] = 1
+		for n in node.childList():
+			self.collectID_recursive(n)
+	def newID(self):
+		while True:
+			n = 's%d' % int(random.random()*10000)
+			#print "try %s" % n
+			if self.ID.has_key(n) == False:
+				return n
+	def dumpID(self):
+		for a,v in self.ID.items():
+			print a
+
+		
+	def getLayer(self, layer):
+		for l in self.layer:
+			if l.node.getId() == layer:
+				return l
+		return None
+		
+	
+	def insertKeyScene(self):
+		"""
+		Insert a new key scene into the stage. If the nth is always a key scene, we will return without changing anything. 
+		If the nth is a filled scene, we will break the original scene into two parts. If the nth is out of any scene, we will
+		append a new scene.
+
+		"""
+		nth = self.last_cell.nScene
+		layer = self.getLayer(self.last_cell.layer)
+		x = self.last_cell.nScene
+		y = self.last_cell.nLayer
+		if layer == None: return
+		for i in range(0,len(layer.scene)):
+			s = layer.scene[i]
+			if nth >= s.start and nth <= s.end:
+				if nth == s.start: return
+				newscene = Scene(DuplicateNode(s.node),nth,s.end)
+				newscene.node.setId(self.newID())
+				layer.scene.insert(i+1,newscene)
+				layer.scene[i].end = nth-1
+				btn = self.newCell('start.png')
+				btn.nScene = nth
+				btn.layer = layer
+				btn.nLayer = y
+				self.grid.remove(self.last_cell)
+				self.grid.attach(btn, x,x+1,y,y+1,0,0,0,0)
+				return
+		if len(layer.scene) > 0:
+			last = nth
+			lastscene = None
+			for s in layer.scene:
+				if s.end < nth and last < s.end:
+					last = s.end
+					lastscene = s
+			for x in range(last+1, nth):
+				btn = self.newCell('fill.png')
+				btn.nScene = x
+				btn.layer = layer.node.getId()
+				btn.nLayer = y
+				self.grid.attach(btn, x, x+1, y , y+1,0,0,0,0)
+			if lastscene == None:
+				node = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene')
+				node.setId(self.newID())
+				newscene = Scene(node,nth,nth)
+			else:
+				lastscene.end = nth-1
+				newscene = Scene(DuplicateNode(lastscene.node),nth,nth)
+				newscene.node.setId(self.newID())
+			layer.scene.append(newscene)
+			btn = self.newCell('start.png')
+			x = self.last_cell.nScene
+			y = self.last_cell.nLayer
+			btn.nScene = nth
+			btn.layer = layer.node.getId()
+			btn.nLayer = y
+			self.grid.attach(btn, x, x+1, y, y+1,0,0,0,0)
+		else:
+			# This is the first scene in the layer
+			node = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene')
+			node.repr.setId(self.newID())
+			newscene = Scene(node,nth,nth)
+			layer.scene.append(newscene)
+			btn = self.newCell('start.png')
+			btn.nScene = nth
+			btn.layer = layer.node.getId()
+			btn.nLayer = y
+			self.grid.attach(btn, x, x+1, y, y+1,0,0,0,0)
+
+
+
+
+	def removeKeyScene(self):
+		nth = self.last_cell.nScene
+		try:
+			layer = self.getLayer(self.last_cell.layer)
+		except:
+			return
+		x = self.last_cell.nScene
+		y = self.last_cell.nLayer
+		for i in range(0,len(layer.scene)):
+			s = layer.scene[i]
+			if nth == s.start:
+				if i == 0:
+					for j in range(s.start,s.end+1):
+						btn = self.newCell('empty.png')
+						btn.nScene = nth
+						btn.layer = layer
+						btn.nLayer = y
+						self.grid.attach(btn, j,j+1,y,y+1,0,0,0,0)
+					layer.scene.remove(s)
+				else:
+					if s.start == layer.scene[i-1].end+1:
+						# If the start of the delete scene segment is the end of the last scene segmenet, convert all scenes in the deleted
+						# scene segmenet to the last one
+						layer.scene[i-1].end = s.end
+						layer.scene.remove(s)
+						btn = self.newCell('fill.png')
+
+						btn.nScene = nth
+						btn.layer = layer
+						btn.nLayer = y
+						self.grid.attach(btn, x,x+1,y,y+1,0,0,0,0)
+					else:
+						# Convert all scenes into empty cell
+						layer.scene.remove(s)
+						for j in range(s.start,s.end+1):
+							btn = self.newCell('empty.png')
+							btn.nScene = nth
+							btn.layer = layer
+							btn.nLayer = y
+							self.grid.attach(btn, j,j+1,y,y+1,0,0,0,0)
+
+						
+				return
+
+	def extendScene(self):
+		nth = self.last_cell.nScene
+		try:
+			layer = self.getLayer(self.last_cell.layer)
+		except:
+			traceback.print_exc()
+			return
+		x = self.last_cell.nScene
+		y = self.last_cell.nLayer
+		if layer == None: return
+
+		for i in range(0,len(layer.scene)-1):
+			s = layer.scene[i]
+			if nth >= layer.scene[i].start and nth <= layer.scene[i].end:
+				return
+
+		for i in range(0,len(layer.scene)-1):
+			s = layer.scene[i]
+			if nth >= layer.scene[i].start and nth < layer.scene[i+1].start:
+				for j in range(layer.scene[i].end+1, nth+1):
+					btn = self.newCell('fill.png')
+					btn.nScene = nth
+					btn.nLayer = y
+					btn.layer = self.last_cell.layer
+					self.grid.attach(btn, j,j+1,y,y+1,0,0,0,0)
+				layer.scene[i].end = nth
+				return
+		if len(layer.scene) > 0 and nth > layer.scene[len(layer.scene)-1].end:
+			for j in range(layer.scene[len(layer.scene)-1].end+1, nth+1):
+				btn = self.newCell('fill.png')
+				btn.nScene = nth
+				btn.nLayer = y
+				btn.layer = self.last_cell.layer
+				self.grid.attach(btn, j,j+1,y,y+1,0,0,0,0)
+			layer.scene[len(layer.scene)-1].end = nth
+	def setCurrentScene(self,nth):
+		self.current = nth
+		for layer in self.layer:
+			for s in layer.scene:
+				if nth >= s.start and nth <= s.end:
+					s.node.repr.setAttribute("style","",True)
+					#print "Put the elemenets out"
+					layer.nodes = []
+
+					#for o in s.node:
+						#print "    ",o.tag
+					#	layer.nodes.append(o)
+					#for o in s.node:
+					#	s.node.remove(o)
+				else:
+					s.node.repr.setAttribute("style","display:none",True)
+	def generate(self):
+		newdoc = deepcopy(self.document)
+		root = newdoc.getroot()
+		has_scene = False
+		for n in root:
+			if n.tag == '{http://www.w3.org/2000/svg}metadata':
+				for nn in n:
+					if nn.tag == '{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scenes':
+						nn.clear()
+						nn.set("current", "%d" % self.current)
+						scenes = []
+						for l in self.layer:
+							for s in l.scene:
+								id = s.node.get("id")
+								scene = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene')
+								scene.set("ref", id)
+								if s.start == s.end:
+									scene.set("start", "%d" % s.start)
+								else:
+									scene.set("start", "%d" % s.start)
+									scene.set("end", "%d" % s.end)
+
+								scenes.append(scene)
+						for s in scenes:
+							nn.append(s)
+						has_scene = True
+				if has_scene == False:
+					scenes = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scenes')
+					scenes.set("current","%d" % self.current)
+					for l in self.layer:
+						for s in l.scene:
+							scene = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene')
+							scene.set("ref", s.node.get("id"))
+							if s.start == s.end:
+								scene.set("start", "%d" % s.start)
+							else:
+								scene.set("start", "%d" % s.start)
+								scene.set("end", "%d" % s.end)
+							scenes.append(scene)
+					n.append(scenes)
+			if n.tag ==  '{http://www.w3.org/2000/svg}g':
+				root.remove(n)
+
+		for l in self.layer:
+			# Duplicate all attribute of the layer
+			lnode = etree.Element("{http://www.w3.org/2000/svg}g")
+			for a,v in l.node.attrib.items():
+				lnode.set(a,v)
+			for n in l.nodes:
+				lnode.append(n)
+			root.append(lnode)
+			for s in l.scene:
+				snode = etree.Element("{http://www.w3.org/2000/svg}g")
+				for a,v in s.node.attrib.items():
+					snode.set(a,v)
+				for n in s.node:
+					snode.append(deepcopy(n))
+				lnode.append(snode)
+		self.document = newdoc
+	def newCell(self,file):
+		img = gtk.Image()
+		img.set_from_file(file)
+		btn = gtk.EventBox()
+		btn.add(img)
+		btn.connect("button_press_event", self.cellSelect)
+		btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray"))
+		return btn
+	def showGrid(self):
+		max = 0
+		for layer in self.layer:
+			for s in layer.scene:
+				if s.end > max:
+					max = s.end
+		max = 50
+
+		self.grid = gtk.Table(len(self.layer)+1, 50)
+		self.scrollwin = gtk.ScrolledWindow()
+		self.scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+		self.scrollwin.add_with_viewport(self.grid)
+		for i in range(1,max):
+			self.grid.attach(gtk.Label('%d'% i), i,i+1,0,1,0,0,0,0)
+		for i in range(1,len(self.layer)+1):
+			print "Layer", i
+			l = self.layer[i-1]
+			#self.grid.attach(gtk.Label(l.node.get('{http://www.inkscape.org/namespaces/inkscape}label')), 0, 1, i, i+1,0,0,10,0)
+			for s in l.scene:
+				btn = self.newCell('start.png')
+				btn.nScene = s.start
+				btn.layer = l.node.getId()
+				btn.nLayer = i
+
+				self.grid.attach(btn, s.start, s.start+1, i, i+1,0,0,0,0)
+				for j in range(s.start+1,s.end+1):
+					btn = self.newCell('fill.png')
+					self.grid.attach(btn, j, j+1, i , i+1,0,0,0,0)
+					btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray"))
+					btn.nScene = j
+					btn.layer = l.node.getId()
+					btn.nLayer = i
+			if len(l.scene) == 0:
+				start = 0
+			else:
+				start = l.scene[len(l.scene)-1].end
+			for j in range(start,max):
+				btn = self.newCell('empty.png')
+				self.grid.attach(btn, j+1, j+2,i,i+1,0,0,0,0)
+				btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray"))
+				btn.nScene = j+1
+				btn.layer = l.node.getId()
+				btn.nLayer = i
+		self.last_cell = None
+	def cellSelect(self, cell, data):
+		if self.last_cell:
+			self.last_cell.modify_bg(gtk.STATE_NORMAL, self.last_cell.get_colormap().alloc_color("gray"))
+			
+		self.last_cell = cell
+		cell.modify_bg(gtk.STATE_NORMAL, cell.get_colormap().alloc_color("green"))
+		
+	def doEditScene(self,w):
+		self.setCurrentScene(self.last_cell.nScene)
+	def doInsertKeyScene(self,w):
+		return
+		self.insertKeyScene()
+		self.grid.show_all()
+
+	def doRemoveScene(self,w):
+		return
+		self.removeKeyScene()
+		self.grid.show_all()
+		self.generate()
+	def doExtendScene(self,w):
+		self.extendScene()
+		self.grid.show_all()
+	def addButtons(self,hbox):
+		btn = gtk.Button('Edit')
+		btn.connect('clicked', self.doEditScene)
+		hbox.pack_start(btn)
+		btn = gtk.Button('Insert Key')
+		btn.connect('clicked',self.doInsertKeyScene)
+		hbox.pack_start(btn)
+		btn=gtk.Button('Remove Key')
+		btn.connect('clicked', self.doRemoveScene)
+		hbox.pack_start(btn)
+		btn=gtk.Button('Extend scene')
+		btn.connect('clicked', self.doExtendScene)
+		hbox.pack_start(btn)
+	def onQuit(self, event):
+		self.OK = False
+		gtk.main_quit()
+	def onOK(self,event):
+		self.OK = True
+		gtk.main_quit()
+
+	def onConfirmDelete(self):
+		if self.scenemap == None:
+			vbox = gtk.VBox()
+			vbox.pack_start(gtk.Label('Convert the SVG into a MadButterfly SVG file. All current element will be delted'))
+			hbox = gtk.HBox()
+			self.button = gtk.Button('OK')
+			hbox.pack_start(self.button)
+			self.button.connect('clicked', self.onOK)
+			self.button = gtk.Button('Cancel')
+			hbox.pack_start(self.button)
+			self.button.connect("clicked", self.onQuit)
+			vbox.pack_start(hbox)
+			self.window.add(vbox)
+			self.window.show_all()
+			gtk.main()
+			self.window.remove(vbox)
+
+
+	def show(self):
+		self.OK = True
+		self.parseScene()
+		self.showGrid()
+		#self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
+		#self.window.connect("destroy", gtk.main_quit)
+		#self.window.set_position(gtk.WIN_POS_MOUSE)
+		if self.scenemap == None:
+			self.onConfirmDelete()
+		if self.OK:
+			vbox = gtk.VBox()
+			self.window.add(vbox)
+			vbox.add(self.scrollwin)
+			self.vbox = vbox
+			hbox=gtk.HBox()
+			self.addButtons(hbox)
+			vbox.add(hbox)
+		else:
+			return
+
+		self.window.set_size_request(600,200)
+
+		self.window.show_all()
+
+		
Binary file pyink/active-empty.png has changed
Binary file pyink/active-fill.png has changed
Binary file pyink/active-start.png has changed
Binary file pyink/empty.png has changed
Binary file pyink/fill.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pyink/mbtest.svg	Sun Nov 14 23:09:02 2010 +0800
@@ -0,0 +1,322 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:ns0="http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="640px"
+   height="480px"
+   id="svg2383"
+   sodipodi:version="0.32"
+   inkscape:version="0.48+devel r9760 custom"
+   sodipodi:docname="mbtest.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.1">
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.6029106"
+     inkscape:cx="229.53957"
+     inkscape:cy="240.5"
+     inkscape:current-layer="g3380"
+     inkscape:document-units="px"
+     showgrid="false"
+     inkscape:window-width="1400"
+     inkscape:window-height="974"
+     inkscape:window-x="0"
+     inkscape:window-y="25"
+     inkscape:window-maximized="0" />
+  <defs
+     id="defs2385">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3211">
+      <stop
+         style="stop-color:#001dff;stop-opacity:1;"
+         offset="0"
+         id="stop3213" />
+      <stop
+         style="stop-color:#001dff;stop-opacity:0;"
+         offset="1"
+         id="stop3215" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 240 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="640 : 240 : 1"
+       inkscape:persp3d-origin="320 : 160 : 1"
+       id="perspective2391" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211"
+       id="linearGradient3217"
+       x1="31.940987"
+       y1="28.009715"
+       x2="104.68548"
+       y2="28.009715"
+       gradientUnits="userSpaceOnUse" />
+    <filter
+       inkscape:collect="always"
+       id="filter3295">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="0.67110109"
+         id="feGaussianBlur3297" />
+    </filter>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211"
+       id="linearGradient3316"
+       gradientUnits="userSpaceOnUse"
+       x1="31.940987"
+       y1="28.009715"
+       x2="104.68548"
+       y2="28.009715" />
+    <linearGradient
+       y2="28.009715"
+       x2="104.68548"
+       y1="28.009715"
+       x1="31.940987"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3542"
+       xlink:href="#linearGradient3211"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="28.009715"
+       x2="104.68548"
+       y1="28.009715"
+       x1="31.940987"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3544"
+       xlink:href="#linearGradient3211"
+       inkscape:collect="always" />
+    <filter
+       height="1.34432"
+       y="-0.17216"
+       width="1.0257982"
+       x="-0.012899101"
+       id="filter3854"
+       inkscape:collect="always">
+      <feGaussianBlur
+         id="feGaussianBlur3856"
+         stdDeviation="3.3563945"
+         inkscape:collect="always" />
+    </filter>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0"
+       id="linearGradient3316-4"
+       gradientUnits="userSpaceOnUse"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714" />
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3211-0">
+      <stop
+         style="stop-color:#001dff;stop-opacity:1;"
+         offset="0"
+         id="stop3213-3" />
+      <stop
+         style="stop-color:#001dff;stop-opacity:0;"
+         offset="1"
+         id="stop3215-9" />
+    </linearGradient>
+    <filter
+       color-interpolation-filters="sRGB"
+       inkscape:collect="always"
+       id="filter3295-1">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="0.67110109"
+         id="feGaussianBlur3297-9" />
+    </filter>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3211-0"
+       id="linearGradient3217-6"
+       x1="31.940987"
+       y1="28.009714"
+       x2="104.68548"
+       y2="28.009714"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <metadata
+     id="metadata2388">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+    <ns0:scenes
+       current="1">
+      <ns0:scene
+         end="2"
+         start="1"
+         ref="s4393" />
+      <ns0:scene
+         start="1"
+         ref="s4427" />
+      <ns0:scene
+         start="2"
+         ref="s4159" />
+    </ns0:scenes>
+  </metadata>
+  <g
+     inkscape:groupmode="layer"
+     id="layer2"
+     inkscape:label="Background"
+     style="display:none">
+    <rect
+       style="fill:#00ffff;fill-opacity:1;stroke:#000000;stroke-opacity:1"
+       id="rect2437"
+       width="641.95721"
+       height="481.62387"
+       x="0"
+       y="-0.37614822" />
+    <rect
+       ry="10"
+       rx="10"
+       y="10.780138"
+       x="8.5505733"
+       height="46.789886"
+       width="624.48901"
+       id="rect3700"
+       style="fill:#ff831d;fill-opacity:1;stroke:none;filter:url(#filter3854)" />
+    <rect
+       ry="10"
+       rx="10"
+       y="5.8625031"
+       x="6.8625164"
+       height="46.789886"
+       width="624.48901"
+       id="rect3698"
+       style="fill:#ffcc1d;fill-opacity:1;stroke:none" />
+    <g
+       id="s4393"
+       style="" />
+    <g
+       transform="translate(-8.8900812,0.1559783)"
+       id="g3303">
+      <rect
+         y="15.22048"
+         x="32.440987"
+         height="25.57847"
+         width="71.744492"
+         id="rect2439"
+         style="fill:url(#linearGradient3217-6);fill-opacity:1;stroke:none;filter:url(#filter3295-1)" />
+      <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>
+    <g
+       id="g3308"
+       transform="translate(79.386834,0.4679103)">
+      <rect
+         y="15.22048"
+         x="32.440987"
+         height="25.57847"
+         width="71.744492"
+         id="rect3310"
+         style="fill:url(#linearGradient3316-4);fill-opacity:1;stroke:none;filter:url(#filter3295-1)" />
+      <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:groupmode="layer"
+     id="layer3"
+     inkscape:label="Buton"
+     style="display:inline">
+    <g
+       id="s4427"
+       style="display:none" />
+    <g
+       id="s4159"
+       transform="translate(170.31517,0.62386544)"
+       style="">
+      <g
+         transform="translate(4.9909171,0.3119319)"
+         id="g3370">
+        <rect
+           style="fill:url(#linearGradient3542);fill-opacity:1;stroke:none;filter:url(#filter3295)"
+           id="rect3372"
+           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="35.927368"
+           y="33.312569"
+           id="text3374"><tspan
+             sodipodi:role="line"
+             id="tspan3376"
+             x="35.927368"
+             y="33.312569"
+             style="font-size:16px">GNOME</tspan></text>
+      </g>
+      <g
+         transform="translate(102.93775,-0.9357981)"
+         id="g3380">
+        <rect
+           style="fill:url(#linearGradient3544);fill-opacity:1;stroke:none;filter:url(#filter3295)"
+           id="rect3382"
+           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="text3384"><tspan
+             sodipodi:role="line"
+             id="tspan3386"
+             x="39.927368"
+             y="33.312569"
+             style="font-size:16px">AAA</tspan></text>
+      </g>
+    </g>
+  </g>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     style="display:inline" />
+</svg>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pyink/pyink.py	Sun Nov 14 23:09:02 2010 +0800
@@ -0,0 +1,25 @@
+import pybInkscape
+import pygtk
+import gtk
+from MBScene import *
+global ink_inited
+ink_inited=0
+def start_desktop(inkscape,ptr):
+    global ink_inited
+    if ink_inited == 1:
+        return
+        
+    desktop = pybInkscape.GPointer_2_PYSPDesktop(ptr)
+    top = desktop.getToplevel()
+    dock = desktop.getDock()
+    item = dock.new_item("scene", "scene", "feBlend-icon", dock.ITEM_ST_DOCKED_STATE)
+
+    ink_inited = 1
+    scene = MBScene(desktop,item.get_vbox())
+    scene.show()
+
+
+def pyink_start():
+    print 'pyink_start()'
+    pybInkscape.inkscape.connect('activate_desktop', start_desktop)
+    pass
Binary file pyink/start.png has changed