On 13/04/2018 at 05:31, xxxxxxxx wrote:
Hi Andreas,
Yeah sure! Let me know if you need anything else!
# Global Variables
PLUGIN_VERSION = 'v1.0'
PLUGIN_ID = 1000010 #TESTING ID
GRP_COMBOXFILES = 1002
GRP_COMBOAXIS = 1003
GRP_ADDBTN = 1004
GRP_AUTOBTN = 1005
GRP_RUNBTN = 1006
OBJLIST = 1021
STATUS = 1031
INITIAL_WIDTH = 100
INITIAL_HEIGHT = 20
TREE_CHECK = 1
TREE_OBJ = 2
TREE_AXIS = 3
TREE_FUNC = 4
PATH = storage.GeGetStartupWritePath() + '/plugins/AO_Tools/eXpressoMachine/res/modules/'
XNODESPATH = sys.path.append(storage.GeGetStartupWritePath() + '/plugins/AO_Tools/eXpressoMaker/res/modules')
MAINBC = c4d.BaseContainer()
##################
# Class which represent an object, aka an item in our list
class PickObjs(object) :
objSel = ""
_selected = False
def __init__(self, objSel) :
self.objSel = objSel
print self.objSel
@property
def IsSelected(self) :
return self._selected
def Select(self) :
self._selected = True
def Deselect(self) :
self._selected = False
def __repr__(self) :
return str(self)
def __str__(self) :
return self.objSel
class ListView(c4d.gui.TreeViewFunctions) :
def __init__(self) :
self.listOfObjs = list() # Store all objects we need to display in this list
def IsResizeColAllowed(self, root, userdata, lColID) :
return True
def IsTristate(self, root, userdata) :
return False
def changeAxis(self, obj) :
print obj
# The user is allowed to move all columns.
# TREEVIEW_MOVE_COLUMN must be set in the container of AddCustomGui.
def IsMoveColAllowed(self, root, userdata, lColID) :
return False
# Return the first element in the hierarchy, or None if there is no element.
def GetFirst(self, root, userdata) :
rValue = None if not self.listOfObjs else self.listOfObjs[0]
return rValue
# Return a child of a node, since we only want a list, we return None everytime
def GetDown(self, root, userdata, obj) :
return None
# Returns the next Object to display after arg:'obj'
def GetNext(self, root, userdata, obj) :
rValue = None
currentObjIndex = self.listOfObjs.index(obj)
nextIndex = currentObjIndex + 1
if nextIndex < len(self.listOfObjs) :
rValue = self.listOfObjs[nextIndex]
return rValue
# Returns the previous Object to display before arg:'obj'
def GetPred(self, root, userdata, obj) :
rValue = None
currentObjIndex = self.listOfObjs.index(obj)
predIndex = currentObjIndex - 1
if 0 <= predIndex < len(self.listOfObjs) :
rValue = self.listOfObjs[predIndex]
return rValue
# Return a unique ID for the element in the TreeView.
def GetId(self, root, userdata, obj) :
return hash(obj)
# Called when the user selects an element.
def Select(self, root, userdata, obj, mode) :
if mode == c4d.SELECTION_NEW:
for tex in self.listOfObjs:
tex.Deselect()
obj.Select()
elif mode == c4d.SELECTION_ADD:
obj.Select()
elif mode == c4d.SELECTION_SUB:
obj.Deselect()
def IsSelected(self, root, userdata, obj) :
"""
Returns: True if *obj* is selected, False if not.
"""
return obj.IsSelected
# Called when the user clicks on a checkbox for an object in a c4d.LV_CHECKBOX` column.
def SetCheck(self, root, userdata, obj, column, checked, msg) :
if checked:
obj.Select()
else:
obj.Deselect()
# Returns: (int) : Status of the checkbox in the specified *column* for *obj*.
def IsChecked(self, root, userdata, obj, column) :
if obj.IsSelected:
return c4d.LV_CHECKBOX_CHECKED | c4d.LV_CHECKBOX_ENABLED
else:
return c4d.LV_CHECKBOX_ENABLED
# Returns the name to display for arg:'obj', only called for column of type LV_TREE
def GetName(self, root, userdata, obj) :
return str(obj)
# Create all context menu values (Mouse Right Click)
def CreateContextMenu(self, root, userdata, obj, lColumn, bc) :
bc.RemoveData(900001) # Remove all option
# Draw into a Cell, only called for column of type LV_USER
def DrawCell(self, root, userdata, obj, col, drawinfo, bgColor) :
if col == TREE_OBJ:
name = obj.GetName()
geUserArea = drawinfo["frame"]
w = geUserArea.DrawGetTextWidth(name)
h = geUserArea.DrawGetFontHeight()
xpos = drawinfo["xpos"]
ypos = drawinfo["ypos"] + drawinfo["height"]
drawinfo["frame"].DrawText(name, xpos, ypos - h * 1.1)
elif col == TREE_AXIS:
name = obj.GetName()
geUserArea = drawinfo["frame"]
w = geUserArea.DrawGetTextWidth(name)
h = geUserArea.DrawGetFontHeight()
xpos = drawinfo["xpos"]
ypos = drawinfo["ypos"] + drawinfo["height"]
drawinfo["frame"].DrawText(name, xpos, ypos - h * 1.1)
elif col == TREE_FUNC:
name = obj.GetName()
geUserArea = drawinfo["frame"]
w = geUserArea.DrawGetTextWidth(name)
h = geUserArea.DrawGetFontHeight()
xpos = drawinfo["xpos"]
ypos = drawinfo["ypos"] + drawinfo["height"]
drawinfo["frame"].DrawText(name, xpos, ypos - h * 1.1)
# Called when a delete event is received.
def DeletePressed(self, root, userdata) :
for obj in reversed(self.listOfObjs) :
if obj.IsSelected:
self.listOfObjs.remove(obj)
# Main class for the plugin dialog (UI).
class eXpressoMakerDialog(gui.GeDialog) :
_treegui = None # Our CustomGui TreeView
_listView = ListView() # Our Instance of c4d.gui.TreeViewFunctions
# Create the dialog's layout
def CreateLayout(self) :
self.SetTitle('eXpresso Machine ' + PLUGIN_VERSION) # Title name
################### Main group container for all the widgets.
self.GroupBegin(10000, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT, 1, 1, 'MainGroup')
################ Combo box that gets the sub-modules from the modules folder.
self.GroupBegin(10001, c4d.BFH_SCALEFIT, 1, 1, 'Function')
self.GroupBorder(c4d.BORDER_GROUP_OUT)
self.GroupBorderSpace(10, 10, 10, 10)
self.AddComboBox(GRP_COMBOXFILES, c4d.BFH_SCALEFIT, INITIAL_WIDTH, INITIAL_HEIGHT)
# Get all the modules in list and add it as a child of the combo box.
filesSubID = 0
for file in listFiles() :
self.AddChild(GRP_COMBOXFILES, filesSubID, file)
filesSubID += 1
self.GroupEnd()
################
################ Selection group container.
self.GroupBegin(10002, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT, 2, 1, 'Selection')
self.GroupBorder(c4d.BORDER_GROUP_OUT)
self.GroupBorderSpace(10, 10, 10, 10)
############# Main menu buttons group container.
self.GroupBegin(10020, c4d.BFV_SCALEFIT, 1, 1, 'Menu')
########## Axis layout group container, combo box and button.
self.GroupBegin(10021, c4d.BFH_SCALEFIT, 1, 1, 'Axis')
self.GroupBorder(c4d.BORDER_GROUP_OUT)
self.GroupBorderSpace(10, 10, 10, 10)
self.AddComboBox(GRP_COMBOAXIS, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT, 30, INITIAL_HEIGHT)
# Get all the axis in list and add it as a child of the combo box.
axisID = 0
global axisList
axisList = ['X', 'Y', 'Z']
for axis in axisList:
self.AddChild(GRP_COMBOAXIS, axisID, axis)
axisID += 1
self.GroupEnd()
##########
########## Objects layout group container and function buttons.
self.GroupBegin(10022, c4d.BFH_SCALEFIT, 1, 1, 'Objects')
self.GroupBorder(c4d.BORDER_GROUP_OUT)
self.GroupBorderSpace(10, 10, 10, 10)
self.AddButton(GRP_AUTOBTN, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT, INITIAL_WIDTH, INITIAL_HEIGHT, 'Auto-Find')
self.AddButton(GRP_ADDBTN, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT, INITIAL_WIDTH, INITIAL_HEIGHT, 'Add')
self.GroupEnd()
##########
self.GroupEnd()
#############
############# Object TreeView container, where list of object, axis and function selection will be displayed. Each line is selectable and mutable.
self.GroupBegin(10023, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT, 1, 1, 'Object List')
treeViewGUI = c4d.BaseContainer()
treeViewGUI.SetBool(c4d.TREEVIEW_BORDER, c4d.BORDER_THIN_IN)
treeViewGUI.SetBool(c4d.TREEVIEW_BORDER, True)
treeViewGUI.SetBool(c4d.TREEVIEW_HAS_HEADER, True)
treeViewGUI.SetBool(c4d.TREEVIEW_HIDE_LINES, True)
treeViewGUI.SetBool(c4d.TREEVIEW_MOVE_COLUMN, True)
treeViewGUI.SetBool(c4d.TREEVIEW_RESIZE_HEADER, True)
treeViewGUI.SetBool(c4d.TREEVIEW_FIXED_LAYOUT, True)
treeViewGUI.SetBool(c4d.TREEVIEW_ALTERNATE_BG, True)
self._treegui = self.AddCustomGui(OBJLIST, c4d.CUSTOMGUI_TREEVIEW, "", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 400, 0, treeViewGUI)
self.GroupEnd()
#############
self.GroupEnd()
################
################ Status group container, where informs the user about the function actions.
self.GroupBegin(10003, c4d.BFH_SCALEFIT, 1, 1)
self.AddStaticText(STATUS, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT)
self.GroupEnd()
################
################ Run group container that includes the main button to run all of the list functions.
self.GroupBegin(10004, c4d.BFH_SCALEFIT, 1, 1)
self.AddSeparatorV(INITIAL_WIDTH, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT)
self.AddButton(GRP_RUNBTN, c4d.BFV_SCALEFIT | c4d.BFH_SCALEFIT, INITIAL_WIDTH, INITIAL_HEIGHT, 'Run')
self.GroupEnd()
################
self.GroupEnd()
###################
return True
# Initialize default values
def InitValues(self) :
# Initialize the column layout for the TreeView.
layout = c4d.BaseContainer()
layout.SetLong(TREE_CHECK, c4d.LV_CHECKBOX)
layout.SetLong(TREE_OBJ, c4d.LV_TREE)
layout.SetLong(TREE_AXIS, c4d.LV_USER)
layout.SetLong(TREE_FUNC, c4d.LV_USER)
self._treegui.SetLayout(TREE_FUNC, layout)
# Set the header titles.
self._treegui.SetHeaderText(TREE_CHECK, "")
self._treegui.SetHeaderText(TREE_OBJ, "Object")
self._treegui.SetHeaderText(TREE_AXIS, "Axis")
self._treegui.SetHeaderText(TREE_FUNC, "Function")
self._treegui.Refresh()
# Set TreeViewFunctions instance used by our CUSTOMGUI_TREEVIEW
self._treegui.SetRoot(self._treegui, self._listView, None)
return True
# Iterate through all the scene objects that include the words 'PIVOT' and 'MOVE' and append it to a list.
def getObjs(self, op, output) :
while op:
if 'PIVOT' in op.GetName().upper() or 'MOVE' in op.GetName().upper() :
output.append(op)
self.getObjs(op.GetDown(),output)
op = op.GetNext()
return output
# Return the correct ID for the axis selected.
def getAxis(self, axis) :
selAxis = {'X' : 'c4d.VECTOR_X', # ID: 1000
'Y' : 'c4d.VECTOR_Y', # ID: 1001
'Z' : 'c4d.VECTOR_Z'} # ID: 1002
return selAxis[axis]
'''NOT USED
def CoreMessage(self, id, msg) :
return gui.GeDialog.CoreMessage(self, id, msg)
'''
# Built-In function to run events when triggered by the dialog widgets.
def Command(self, id, msg) :
fileSelectedIndex = self.GetInt32(GRP_COMBOXFILES) # Get the function combo box index for the value selected.
axisSelectedIndex = self.GetInt32(GRP_COMBOAXIS) # Get the axis combo box index for the value selected.
doc = c4d.documents.GetActiveDocument() # Get active document.
# Event trigger for the axis combo box and button.
if (id == GRP_COMBOAXIS) :
if self._listView.listOfObjs != []:
i = 0
for obj in self._listView.listOfObjs:
print self._listView.changeAxis(obj)
self.SetString(STATUS, 'Axis changed!') # Event run, show the event message to the user.
else:
self.SetString(STATUS, 'No objects to change the axis!') # If no objects are on list, show the event message to the user.
# Event trigger for the add button.
if (id == GRP_ADDBTN) :
selObjs = doc.GetActiveObjects(0) # Get a list of selected objects.
if selObjs != []:
# Add data to our DataStructure (ListView)
for obj in selObjs:
newID = len(self._listView.listOfObjs) + 1
objName = obj.GetName()
axisName = axisList[axisSelectedIndex].upper()
funcName = str(files[fileSelectedIndex])
self._listView.listOfObjs.append([objName, axisName, funcName])
for objSel in self._listView.listOfObjs:
for value in objSel:
PickObjs(value)
# Refresh the TreeView
self._treegui.Refresh()
self.SetString(STATUS, 'Object(s) added!') # Event run, show the event message to the user.
else:
self.SetString(STATUS, 'No objects selected!') # If no objects are on list, show the event message to the user.
if (id == GRP_AUTOBTN) :
parentObjs = doc.GetObjects() # Get a list of all parent objects of the scene.
selObjs = []
if parentObjs != []:
# Get all the objects that have the word 'PIVOT' or 'MOVE' on its name.
# Case sensitivity is not a a problem, as the function converts the name to upper case.
self.getObjs(parentObjs[0], selObjs)
if selObjs != []:
# Add data to our DataStructure (ListView)
for obj in selObjs:
newID = len(self._listView.listOfObjs) + 1
objName = PickObjs(obj.GetName(), axisList[axisSelectedIndex].upper(), str(files[fileSelectedIndex]))
self._listView.listOfObjs.append(objName)
# Refresh the TreeView
self._treegui.Refresh()
self.SetString(STATUS, 'Object(s) Added') # Event run, show the event message to the user.
else:
self.SetString(STATUS, 'Could not find any objects!') # If no objects are on list, show the event message to the user.
else:
self.SetString(STATUS, 'Could not find any objects!') # If no objects are on list, show the event message to the user.
if (id == GRP_COMBOXFILES) :
prevMsg = self.GetString(OBJLIST) # Get the list (message) from the multi-line widget.
if prevMsg != '':
self.SetString(STATUS, 'Function changed to ' + str(files[fileSelectedIndex])) # Event run, show the event message to the user.
else:
self.SetString(STATUS, 'No objects selected!') # If no objects are on list, show the event message to the user.
if (id == GRP_RUNBTN) :
prevMsg = self.GetString(OBJLIST) # Get the list (message) from the multi-line widget.
if prevMsg != '':
with localimport('res/modules') :
lines = prevMsg.split('\n') # Split the line by the new line character into different sections.
del lines[-1] # Delete the last empty line.
lineIndex = 0
for line in lines:
wordList = line.split() # Split the line into different sections.
# Freeze the transformations for of the object.
for id, value in MAINBC:
if id == lineIndex:
objBC = MAINBC.GetData(id)
for id, value in objBC:
print id, value
if wordList[-1] not in sys.modules:
__import__(wordList[-1]) # Call the correct model to run.
else:
reload(__import__(wordList[-1])) # If the module modified, reload the model and run it.
lineIndex += 1
self.SetString(STATUS, 'Rig done!') # Event run, show the event message to the user.
else:
self.SetString(STATUS, 'No objects selected!') # If no objects are on list, show the event message to the user.
return True
# Return the relevant list of objects that contain the file extension '.py'
# and do not start with the file name '__innit__'
def listFiles() :
global files
files = []
if os.path.exists(PATH) :
for file in os.listdir(PATH) :
if file.endswith('.py') and os.path.splitext(file)[0] != '__init__':
files.append(os.path.splitext(file)[0])
return files
# Open the plugin in a new window when the main plugin function is called
class eXpressoMakerPlugin(plugins.CommandData) :
dialog = None
# Creates the dialog
def Execute(self, doc) :
if self.dialog is None:
self.dialog = eXpressoMakerDialog()
return self.dialog.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID, defaultw=300, defaulth=150, xpos=-1, ypos=-1)
# Manages the dialog
def RestoreLayout(self, sec_ref) :
if self.dialog is None:
self.dialog = eXpressoMakerDialog()
return self.dialog.Restore(PLUGIN_ID, secret=sec_ref)
if __name__ == '__main__':
path, fn = os.path.split(__file__)
bmp = bitmaps.BaseBitmap() # We need an instance of BaseBitmap class to use an image
bmp.InitWith(os.path.join(path, 'res/icons/', 'icon.tif')) # The location where the menu image exists
okyn = plugins.RegisterCommandPlugin(PLUGIN_ID, 'eXpresso Machine ' + PLUGIN_VERSION, 0, bmp, 'eXpresso Machine ' + PLUGIN_VERSION, eXpressoMakerPlugin())
if (okyn) :
print 'eXpresso Machine ' + PLUGIN_VERSION + ' Loaded!'
c4d.StatusSetText('eXpresso Machine ' + PLUGIN_VERSION + ' Loaded!')
Thank you very much Andreas! :slightly_smiling_face: