502 lines
11 KiB
Python
Executable File
502 lines
11 KiB
Python
Executable File
#!BPY
|
|
|
|
"""
|
|
Name: 'ID Property Browser'
|
|
Blender: 242
|
|
Group: 'Help'
|
|
Tooltip: 'Browse ID properties'
|
|
"""
|
|
|
|
__author__ = "Joe Eagar"
|
|
__version__ = "0.3.108"
|
|
__email__ = "joeedh@gmail.com"
|
|
__bpydoc__ = """\
|
|
|
|
Allows browsing, creating and editing of ID Properties
|
|
for various ID block types such as mesh, scene, object,
|
|
etc.
|
|
"""
|
|
|
|
|
|
from Blender import *
|
|
from Blender.BGL import *
|
|
from Blender.Types import IDGroupType, IDArrayType
|
|
import Blender
|
|
|
|
def IsInRectWH(mx, my, x, y, wid, hgt):
|
|
if mx >= x and mx <= x + wid:
|
|
if my >= y and my <= y + hgt:
|
|
return 1
|
|
return 0
|
|
|
|
Button_Back = 1
|
|
Button_New = 2
|
|
Button_MatMenu = 3
|
|
Button_TypeMenu = 4
|
|
|
|
ButStart = 55
|
|
|
|
IDP_String = 0
|
|
IDP_Int = 1
|
|
IDP_Float = 2
|
|
IDP_Array = 5
|
|
IDP_Group = 6
|
|
|
|
ButDelStart = 255
|
|
#max limit for string input button
|
|
strmax = 100
|
|
|
|
State_Normal = 0
|
|
State_InArray = 1
|
|
|
|
#IDTypeModules entries are of form [module, active_object_index, module_name]
|
|
IDTypeModules = [[Scene, 0, "Scenes"], [Object, 0, "Objects"], [Mesh, 0, "Meshes"]]
|
|
IDTypeModules += [[Material, 0, "Materials"], [Texture, 0, "Textures"]]
|
|
IDTypeModules += [[Image, 0, "Images"]]
|
|
|
|
class IDArrayBrowser:
|
|
array = 0
|
|
parentbrowser = 0
|
|
buts = 0
|
|
|
|
def __init__(self):
|
|
self.buts = []
|
|
|
|
def Draw(self):
|
|
pb = self.parentbrowser
|
|
x = pb.x
|
|
y = pb.y
|
|
width = pb.width
|
|
height = pb.height
|
|
pad = pb.pad
|
|
itemhgt = pb.itemhgt
|
|
cellwid = 65
|
|
y = y + height - itemhgt - pad
|
|
|
|
Draw.PushButton("Back", Button_Back, x, y, 40, 20)
|
|
y -= itemhgt + pad
|
|
|
|
self.buts = []
|
|
Draw.BeginAlign()
|
|
for i in xrange(len(self.array)):
|
|
st = ""
|
|
if type(self.array[0]) == float:
|
|
st = "%.5f" % self.array[i]
|
|
else: st = str(self.array[i])
|
|
|
|
b = Draw.String("", ButStart+i, x, y, cellwid, itemhgt, st, 30)
|
|
self.buts.append(b)
|
|
x += cellwid + pad
|
|
if x + cellwid + pad > width:
|
|
x = 0
|
|
y -= itemhgt + pad
|
|
Draw.EndAlign()
|
|
def Button(self, bval):
|
|
if bval == Button_Back:
|
|
self.parentbrowser.state = State_Normal
|
|
self.parentbrowser.array = 0
|
|
self.buts = []
|
|
Draw.Draw()
|
|
self.array = 0
|
|
elif bval >= ButStart:
|
|
i = bval - ButStart
|
|
st = self.buts[i].val
|
|
n = 0
|
|
if type(self.array[0]) == float:
|
|
try:
|
|
n = int(st)
|
|
except:
|
|
return
|
|
elif type(self.array[0]) == int:
|
|
try:
|
|
n = float(st)
|
|
except:
|
|
return
|
|
|
|
self.array[i] = n
|
|
Draw.Draw()
|
|
|
|
def Evt(self, evt, val):
|
|
if evt == Draw.ESCKEY:
|
|
Draw.Exit()
|
|
|
|
class IDPropertyBrowser:
|
|
width = 0
|
|
height = 0
|
|
x = 0
|
|
y = 0
|
|
scrollx = 0
|
|
scrolly = 0
|
|
itemhgt = 22
|
|
pad = 2
|
|
|
|
group = 0
|
|
parents = 0 #list stack of parent groups
|
|
active_item = -1
|
|
mousecursor = 0
|
|
_i = 0
|
|
buts = []
|
|
|
|
state = 0
|
|
array = 0
|
|
prop = 0
|
|
|
|
IDList = 0
|
|
idindex = 0
|
|
idblock = 0
|
|
|
|
type = 0 # attach buildin type() method to class
|
|
# since oddly it's not available to button
|
|
# callbacks! EEK! :(
|
|
|
|
def __init__(self, idgroup, mat, x, y, wid, hgt):
|
|
self.group = idgroup
|
|
self.prop = idgroup
|
|
self.x = x
|
|
self.y = y
|
|
self.width = wid
|
|
self.height = hgt
|
|
self.mousecursor = [0, 0]
|
|
self.parents = []
|
|
self.idblock = mat
|
|
self.type = type
|
|
|
|
def DrawBox(self, glmode, x, y, width, height):
|
|
glBegin(glmode)
|
|
glVertex2f(x, y)
|
|
glVertex2f(x+width, y)
|
|
glVertex2f(x+width, y+height)
|
|
glVertex2f(x, y+height)
|
|
glEnd()
|
|
|
|
def Draw(self):
|
|
global IDTypeModules
|
|
|
|
#first draw outlining box :)
|
|
glColor3f(0, 0, 0)
|
|
self.DrawBox(GL_LINE_LOOP, self.x, self.y, self.width, self.height)
|
|
|
|
itemhgt = self.itemhgt
|
|
pad = self.pad
|
|
x = self.x
|
|
y = self.y + self.height - itemhgt - pad
|
|
|
|
if self.state == State_InArray:
|
|
self.array.Draw()
|
|
return
|
|
|
|
plist = []
|
|
self.buts = []
|
|
for p in self.group.iteritems():
|
|
plist.append(p)
|
|
|
|
#-------do top buttons----------#
|
|
Draw.BeginAlign()
|
|
Draw.PushButton("New", Button_New, x, y, 40, 20)
|
|
x += 40 + pad
|
|
#do the menu button for all materials
|
|
st = ""
|
|
|
|
blocks = IDTypeModules[self.IDList][0].Get()
|
|
i = 1
|
|
mi = 0
|
|
for m in blocks:
|
|
if m.name == self.idblock.name:
|
|
mi = i
|
|
st += m.name + " %x" + str(i) + "|"
|
|
i += 1
|
|
|
|
self.menubut = Draw.Menu(st, Button_MatMenu, x, y, 100, 20, mi)
|
|
|
|
x += 100 + pad
|
|
|
|
st = ""
|
|
i = 0
|
|
for e in IDTypeModules:
|
|
st += e[2] + " %x" + str(i+1) + "|"
|
|
i += 1
|
|
|
|
cur = self.IDList + 1
|
|
self.idmenu = Draw.Menu(st, Button_TypeMenu, x, y, 100, 20, cur)
|
|
x = self.x
|
|
y -= self.itemhgt + self.pad
|
|
Draw.EndAlign()
|
|
|
|
|
|
#-----------do property items---------#
|
|
i = 0
|
|
while y > self.y - 20 - pad and i < len(plist):
|
|
k = plist[i][0]
|
|
p = plist[i][1]
|
|
if i == self.active_item:
|
|
glColor3f(0.5, 0.4, 0.3)
|
|
self.DrawBox(GL_POLYGON, x+pad, y, self.width-pad*2, itemhgt)
|
|
|
|
glColor3f(0, 0, 0)
|
|
self.DrawBox(GL_LINE_LOOP, x+pad, y, self.width-pad*2, itemhgt)
|
|
|
|
glRasterPos2f(x+pad*2, y+5)
|
|
Draw.Text(str(k)) #str(self.mousecursor) + " " + str(self.active_item)) #p.name)
|
|
tlen = Draw.GetStringWidth(str(k))
|
|
|
|
type_p = type(p)
|
|
if type_p == str:
|
|
b = Draw.String("", ButStart+i, x+pad*5+tlen, y, 200, itemhgt, p, strmax)
|
|
self.buts.append(b)
|
|
elif type_p in [int, float]:
|
|
#only do precision to 5 points on floats
|
|
st = ""
|
|
if type_p == float:
|
|
st = "%.5f" % p
|
|
else: st = str(p)
|
|
b = Draw.String("", ButStart+i, x+pad*5+tlen, y, 75, itemhgt, st, strmax)
|
|
self.buts.append(b)
|
|
else:
|
|
glRasterPos2f(x+pad*2 +tlen+10, y+5)
|
|
if type_p == Types.IDArrayType:
|
|
Draw.Text('(array, click to edit)')
|
|
elif type_p == Types.IDGroupType:
|
|
Draw.Text('(group, click to edit)')
|
|
|
|
|
|
self.buts.append(None)
|
|
|
|
Draw.PushButton("Del", ButDelStart+i, x+self.width-35, y, 30, 20)
|
|
|
|
i += 1
|
|
y -= self.itemhgt + self.pad
|
|
|
|
if len(self.parents) != 0:
|
|
Draw.PushButton("Back", Button_Back, x, y, 40, 20)
|
|
x = x + 40 + pad
|
|
|
|
def SetActive(self):
|
|
m = self.mousecursor
|
|
itemhgt = self.itemhgt
|
|
pad = self.pad
|
|
|
|
x = self.x + pad
|
|
y = self.y + self.height - itemhgt - pad - itemhgt
|
|
|
|
plist = []
|
|
for p in self.group.iteritems():
|
|
plist.append(p)
|
|
|
|
self.active_item = -1
|
|
i = 0
|
|
while y > self.y and i < len(plist):
|
|
p = plist[i]
|
|
if IsInRectWH(m[0], m[1], x, y, self.width-pad, itemhgt):
|
|
self.active_item = i
|
|
|
|
i += 1
|
|
y -= self.itemhgt + self.pad
|
|
|
|
def EventIn(self, evt, val):
|
|
if self.state == State_InArray:
|
|
self.array.Evt(evt, val)
|
|
|
|
if evt == Draw.ESCKEY:
|
|
Draw.Exit()
|
|
if evt == Draw.MOUSEX or evt == Draw.MOUSEY:
|
|
size = Buffer(GL_FLOAT, 4)
|
|
glGetFloatv(GL_SCISSOR_BOX, size)
|
|
if evt == Draw.MOUSEX:
|
|
self.mousecursor[0] = val - size[0]
|
|
else:
|
|
self.mousecursor[1] = val - size[1]
|
|
del size
|
|
|
|
self.SetActive()
|
|
self._i += 1
|
|
if self._i == 5:
|
|
Draw.Draw()
|
|
self._i = 0
|
|
|
|
|
|
if evt == Draw.LEFTMOUSE and val == 1:
|
|
plist = list(self.group.iteritems())
|
|
a = self.active_item
|
|
if a >= 0 and a < len(plist):
|
|
p = plist[a]
|
|
|
|
basictypes = [IDGroupType, float, str, int]
|
|
if type(p[1]) == IDGroupType:
|
|
self.parents.append(self.group)
|
|
self.group = p[1]
|
|
self.active_item = -1
|
|
Draw.Draw()
|
|
elif type(p[1]) == IDArrayType:
|
|
self.array = IDArrayBrowser()
|
|
self.array.array = p[1]
|
|
self.array.parentbrowser = self
|
|
self.state = State_InArray
|
|
Draw.Draw()
|
|
|
|
if evt == Draw.TKEY and val == 1:
|
|
try:
|
|
self.prop['float'] = 0.0
|
|
self.prop['int'] = 1
|
|
self.prop['string'] = "hi!"
|
|
self.prop['float array'] = [0, 0, 1.0, 0]
|
|
self.prop['int array'] = [0, 0, 0, 0]
|
|
self.prop.data['a subgroup'] = {"int": 0, "float": 0.0, "anothergroup": {"a": 0.0, "intarr": [0, 0, 0, 0]}}
|
|
Draw.Draw()
|
|
except:
|
|
Draw.PupMenu("Can only do T once per block, the test names are already taken!")
|
|
|
|
|
|
def Button(self, bval):
|
|
global IDTypeModules
|
|
if self.state == State_InArray:
|
|
self.array.Button(bval)
|
|
return
|
|
|
|
if bval == Button_MatMenu:
|
|
global IDTypeModules
|
|
|
|
val = self.idindex = self.menubut.val - 1
|
|
i = self.IDList
|
|
block = IDTypeModules[i][0].Get()[val]
|
|
self.idblock = block
|
|
self.prop = block.properties
|
|
self.group = self.prop
|
|
self.active_item = -1
|
|
self.parents = []
|
|
Draw.Draw()
|
|
|
|
if bval == Button_TypeMenu:
|
|
i = IDTypeModules[self.idmenu.val-1]
|
|
if len(i[0].Get()) == 0:
|
|
Draw.PupMenu("Error%t|There are no " + i[2] + "!")
|
|
return
|
|
|
|
IDTypeModules[self.IDList][1] = self.idindex
|
|
self.IDList = self.idmenu.val-1
|
|
val = self.idindex = IDTypeModules[self.IDList][1]
|
|
i = self.IDList
|
|
block = IDTypeModules[i][0].Get()[val]
|
|
self.idblock = block
|
|
self.prop = block.properties
|
|
self.group = self.prop
|
|
self.active_item = -1
|
|
self.parents = []
|
|
Draw.Draw()
|
|
|
|
if bval >= ButDelStart:
|
|
plist = [p for p in self.group]
|
|
prop = plist[bval - ButDelStart]
|
|
del self.group[prop]
|
|
Draw.Draw()
|
|
|
|
elif bval >= ButStart:
|
|
plist = list(self.group.iteritems())
|
|
|
|
prop = plist[bval - ButStart]
|
|
print prop
|
|
|
|
if self.type(prop[1]) == str:
|
|
self.group[prop[0]] = self.buts[bval - ButStart].val
|
|
elif self.type(prop[1]) == int:
|
|
i = self.buts[bval - ButStart].val
|
|
try:
|
|
i = int(i)
|
|
self.group[prop[0]] = i
|
|
except:
|
|
Draw.Draw()
|
|
return
|
|
Draw.Draw()
|
|
elif self.type(prop[1]) == float:
|
|
f = self.buts[bval - ButStart].val
|
|
try:
|
|
f = float(f)
|
|
self.group[prop[0]] = f
|
|
except:
|
|
Draw.Draw()
|
|
return
|
|
Draw.Draw()
|
|
|
|
elif bval == Button_Back:
|
|
self.group = self.parents[len(self.parents)-1]
|
|
self.parents.pop(len(self.parents)-1)
|
|
Draw.Draw()
|
|
|
|
elif bval == Button_New:
|
|
name = Draw.Create("untitled")
|
|
stype = Draw.Create(0)
|
|
gtype = Draw.Create(0)
|
|
ftype = Draw.Create(0)
|
|
itype = Draw.Create(0)
|
|
atype = Draw.Create(0)
|
|
|
|
block = []
|
|
block.append(("Name: ", name, 0, 30, "Click to type in the name of the new ID property"))
|
|
block.append("Type")
|
|
block.append(("String", stype))
|
|
block.append(("Subgroup", gtype))
|
|
block.append(("Float", ftype))
|
|
block.append(("Int", itype))
|
|
block.append(("Array", atype))
|
|
|
|
retval = Blender.Draw.PupBlock("New IDProperty", block)
|
|
if retval == 0: return
|
|
|
|
name = name.val
|
|
i = 1
|
|
stop = 0
|
|
while stop == 0:
|
|
stop = 1
|
|
for p in self.group:
|
|
if p == name:
|
|
d = name.rfind(".")
|
|
if d != -1:
|
|
name = name[:d]
|
|
name = name + "." + str(i).zfill(3)
|
|
i += 1
|
|
stop = 0
|
|
|
|
type = "String"
|
|
if stype.val:
|
|
self.group[name] = ""
|
|
elif gtype.val:
|
|
self.group[name] = {}
|
|
elif ftype.val:
|
|
self.group[name] = 0.0
|
|
elif itype.val:
|
|
self.group[name] = 0 #newProperty("Int", name, 0)
|
|
elif atype.val:
|
|
arrfloat = Draw.Create(1)
|
|
arrint = Draw.Create(0)
|
|
arrlen = Draw.Create(3)
|
|
block = []
|
|
block.append("Type")
|
|
block.append(("Float", arrfloat, "Make a float array"))
|
|
block.append(("Int", arrint, "Make an integer array"))
|
|
block.append(("Len", arrlen, 2, 200))
|
|
|
|
if Blender.Draw.PupBlock("Array Properties", block):
|
|
if arrfloat.val:
|
|
tmpl = 0.0
|
|
elif arrint.val:
|
|
tmpl = 0
|
|
else:
|
|
return
|
|
|
|
self.group[name] = [tmpl] * arrlen.val
|
|
|
|
|
|
def Go(self):
|
|
Draw.Register(self.Draw, self.EventIn, self.Button)
|
|
|
|
scenes = Scene.Get()
|
|
|
|
size = Window.GetAreaSize()
|
|
browser = IDPropertyBrowser(scenes[0].properties, scenes[0], 2, 2, size[0], size[1])
|
|
browser.Go()
|
|
|
|
#a = prop.newProperty("String", "hwello!", "bleh")
|
|
#b = prop.newProperty("Group", "subgroup")
|
|
|
|
#for p in prop:
|
|
#print p.name
|