Code PHP:
import c4d
ID_OPERATOR_PYTHON = 1022471
_display_modes = ["DISPLAY_H", "DISPLAY_M", "DISPLAY_HM", "DISPLAY_HMS"]
NODE_CODE = """import c4d
from datetime import datetime, timedelta
import re
CONTAINER_ID = 1033688
ELAPSED_SEC = 100
ELAPSED_MICRO = 101
__ENUM_IDS__
_languages = ['fr', 'us']
_strings = {
# User Data
UD_HIDE: {'us':"Hide", 'fr':"Masquer"},
UD_VALUE: {'us':"Value", 'fr':"Valeur"},
UD_RESET: {'us':"Reset", 'fr':"Remise à zéro"},
UD_IDLE: {'us':"Idle", 'fr':"Inactivité"},
UD_TIME_LIMIT: {'us':"Time limit", 'fr':"Limite de temps"},
UD_COUNTDOWN: {'us':"Countdown", 'fr':"Compte à rebours"},
UD_DISPLAY: {'us':"Display", 'fr':"Affichage"},
# Cycles
(UD_DISPLAY, DISPLAY_H): {'us':"Total Hours", 'fr': "Total Heures"},
(UD_DISPLAY, DISPLAY_M): {'us':"Total Minutes", 'fr': "Total Minutes"},
(UD_DISPLAY, DISPLAY_HM): {'us':"Hours:Minutes", 'fr': "Heures:Minutes"},
(UD_DISPLAY, DISPLAY_HMS): {'us':"Hours:Minutes:Seconds", 'fr': "Heures:Minutes:Secondes"},
# Strings
'Show': {'us':"Show", 'fr': "Afficher"},
'Hide': {'us':"Hide", 'fr':"Masquer"},
'Finished': {'us':"Finished", 'fr':"Terminé"},
}
def get_default_language():
i = 0
while True:
lang = c4d.GeGetLanguage(i)
if lang is None:
break
if lang["default_language"]:
lang = lang["extensions"].lower()
return lang if lang in _languages else 'us'
i += 1
def tr(s):
lang = get_default_language().lower()
if s in _strings:
return _strings[s][lang]
return s
def translate_ud(obj, lang):
for desc, bc in obj.GetUserDataContainer():
if not desc[1].id in _strings:
continue
name = _strings[desc[1].id][lang]
bc[c4d.DESC_NAME] = name
bc[c4d.DESC_SHORT_NAME] = name
bc_cycle = bc[c4d.DESC_CYCLE]
if bc_cycle:
for k, v in bc_cycle:
bc_cycle[k] = _strings[(desc[1].id, k)][lang]
bc.SetContainer(c4d.DESC_CYCLE, bc_cycle)
obj.SetUserDataContainer(desc, bc)
_date = None
_total = None
_lang = None
class Duration(timedelta):
@staticmethod
def parse(s=""):
\"""Create timedelta from string.
\"""
regex = r'((?P<hours>\d+):)?((?P<minutes>\d+):?)(?P<seconds>\d+)?'
match_object = re.match(regex, str(s).replace(" ", ""))
if match_object is None:
return Duration()
args = dict((k, int(v)) for k, v in match_object.groupdict(default=0).items())
return Duration(**args)
def __add__(self, x):
y = super(Duration, self).__add__(x)
return Duration(days=y.days, seconds=y.seconds, microseconds=y.microseconds)
def __sub__(self, x):
y = super(Duration, self).__sub__(x)
return Duration(days=y.days, seconds=y.seconds, microseconds=y.microseconds)
def __str__(self):
return self.fmt("{th} : {m} : {s}")
def total_seconds(self, cast=int):
\"""Total seconds from timedelta.
\"""
return (self.microseconds + (self.seconds + self.days * 24 * 3600) * 10 ** 6) / cast(10 ** 6)
def fmt(self, fmt):
\"""String format.
\"""
seconds = self.total_seconds()
d = {'d': self.days}
d['h'], rem = divmod(self.seconds, 3600)
d['m'], d['s'] = divmod(rem, 60)
d['m'] = "{0:02d}".format(d['m'])
d['s'] = "{0:02d}".format(d['s'])
d['th'], d['tm'], d['ts'] = seconds / 3600, seconds / 60, seconds
d['thf'] = "{0:.1f}".format(seconds / 3600.0)
return fmt.format(**d)
def reset(default=Duration()):
global _date
global _total
_total = default
_date = datetime.now()
return default
def get_container(obj, container_id):
bc = obj[container_id]
if not bc:
bc = c4d.BaseContainer()
obj[container_id] = bc
return bc
def init(doc, controller, value):
\"""Init previous date and total elapsed time.
\"""
global _total
global _lang
if _lang is None:
container = get_container(doc, CONTAINER_ID)
_lang = get_default_language().lower()
translate_ud(controller, _lang)
if _total is None:
reset(value)
container = get_container(doc, CONTAINER_ID)
sec, micro = container[ELAPSED_SEC], container[ELAPSED_MICRO]
if sec is not None and micro is not None:
_total = Duration(seconds=sec, microseconds=micro)
elif str(_total) != str(value):
reset(value)
def get_delta():
\"""Return elapsed time from last execution.
\"""
global _date
now = datetime.now()
delta = now - _date
_date = now
return delta
def update(delta, idle, doc, controller):
\"""Update total and ouput.
\"""
global _total
if delta < idle or idle.total_seconds() == 0:
_total += delta
set_ud(controller, UD_VALUE, str(_total))
container = get_container(doc, CONTAINER_ID)
container[ELAPSED_SEC] = _total.total_seconds()
container[ELAPSED_MICRO] = _total.microseconds
doc.GetDataInstance().SetContainer(CONTAINER_ID, container)
def format_time(time_limit, display, countdown):
\"""Format output string.
\"""
global _total
formatted = ""
if _total >= time_limit and time_limit.total_seconds() != 0:
formatted = tr("Finished")
else:
total = _total
if countdown and time_limit.total_seconds() != 0:
total = time_limit - total
fmts = {DISPLAY_M: "{tm}", DISPLAY_H: "{thf}", DISPLAY_HM: "{th}:{m}", DISPLAY_HMS:"{th}:{m}:{s}"}
formatted = total.fmt(fmts[display])
return formatted
def get_ud(op, id_ud):
return op[c4d.ID_USERDATA, id_ud]
def set_ud(op, id_ud, value):
op[c4d.ID_USERDATA, id_ud] = value
def create_layer(obj, name):
layer = c4d.documents.LayerObject()
layer.SetName(name)
layer_root = doc.GetLayerObjectRoot()
layer.InsertUnder(layer_root)
obj.SetLayerObject(layer)
return layer
def hide(doc, obj):
layer = obj.GetLayerObject(doc)
if layer is None:
layer = create_layer(obj, "PointeuseY")
data = layer.GetLayerData(doc)
# Show / Hide Layer
data['manager'] = not data['manager']
layer.SetLayerData(doc, data)
# Switch button name
ud_bc = obj.GetUserDataContainer()
hide_bc, hide_desc = dict((desc[1].id, (bc, desc)) for desc, bc in ud_bc)[UD_HIDE]
names = [tr("Show"), tr("Hide")]
hide_bc[c4d.DESC_NAME] = names[data['manager']]
hide_bc[c4d.DESC_SHORT_NAME] = names[data['manager']]
obj.SetUserDataContainer(hide_desc, hide_bc)
def main():
global __OUTPUT__ # Output Node
controller = op.GetNodeMaster().GetOwner().GetObject()
value = Duration.parse(get_ud(controller, UD_VALUE))
idle = Duration.parse(get_ud(controller, UD_IDLE))
time_limit = Duration.parse(get_ud(controller, UD_TIME_LIMIT))
set_ud(controller, UD_IDLE, str(idle))
set_ud(controller, UD_TIME_LIMIT, str(time_limit))
countdown = get_ud(controller, UD_COUNTDOWN)
display = get_ud(controller, UD_DISPLAY)
if get_ud(controller, UD_RESET):
value = reset()
set_ud(controller, UD_RESET, False)
if get_ud(controller, UD_HIDE):
hide(doc, controller)
set_ud(controller, UD_HIDE, False)
init(doc, controller, value)
delta = get_delta()
update(delta, idle, doc, controller)
__OUTPUT__ = format_time(time_limit, display, countdown)
"""
def create_UD_container(obj, dtype, name, parent):
bc = c4d.GetCustomDataTypeDefault(dtype)
bc[c4d.DESC_NAME] = name
bc[c4d.DESC_SHORT_NAME] = name
bc[c4d.DESC_PARENTGROUP] = parent
return bc
def create_UD_default(obj, bc, default):
bc[c4d.DESC_DEFAULT] = default
ud = obj.AddUserData(bc)
obj[ud] = default
return ud
def create_UD_group(obj, name, parent=None):
bc = create_UD_container(obj, c4d.DTYPE_GROUP, name, parent)
return obj.AddUserData(bc)
def create_UD_string(obj, name, parent=None, default=""):
bc = create_UD_container(obj, c4d.DTYPE_STRING, name, parent)
return create_UD_default(obj, bc, default)
def create_UD_bool(obj, name, parent=None, default=False, gui=c4d.CUSTOMGUI_BOOL):
bc = create_UD_container(obj, c4d.DTYPE_BOOL, name, parent)
bc[c4d.DESC_CUSTOMGUI] = gui
return create_UD_default(obj, bc, default)
def create_UD_cycle(obj, name, parent=None, default=0, populate={}):
bc = create_UD_container(obj, c4d.DTYPE_LONG, name, parent)
bc[c4d.DESC_CUSTOMGUI] = c4d.CUSTOMGUI_CYCLE
items = c4d.BaseContainer()
for i, item in populate.iteritems():
items.SetString(i, item)
bc[c4d.DESC_CYCLE] = items
return create_UD_default(obj, bc, default)
def create_userdata(null):
group = create_UD_group(null, "PointeuseY", c4d.DescID(0))
ud_ids = {}
ud_ids["UD_VALUE"] = create_UD_string(null, "", group, "0:00:00")[1].id
ud_ids["UD_RESET"] = create_UD_bool(null, "", group, gui=c4d.CUSTOMGUI_BUTTON)[1].id
ud_ids["UD_IDLE"] = create_UD_string(null, "", group, "0:05:00")[1].id
ud_ids["UD_TIME_LIMIT"] = create_UD_string(null, "", group, "3:00:00")[1].id
ud_ids["UD_COUNTDOWN"] = create_UD_bool(null, "", group)[1].id
items = dict((i, "dummy") for i, mode in enumerate(_display_modes))
ud_ids["UD_DISPLAY"] = create_UD_cycle(null, "", group, populate=items, default=3)[1].id
ud_ids["UD_HIDE"] = create_UD_bool(null, "", group, gui=c4d.CUSTOMGUI_BUTTON)[1].id
return ud_ids
def create_xpresso(null, ud_ids):
xpresso = c4d.BaseTag(c4d.Texpresso)
null.InsertTag(xpresso)
master = xpresso.GetNodeMaster()
python_node = master.CreateNode(master.GetRoot(), ID_OPERATOR_PYTHON, x=10, y=100)
formatted_port = python_node.AddPort(c4d.GV_PORT_OUTPUT, c4d.OUT_STRING, message=True)
python_node[c4d.GV_PYTHON_CODE] = generate_code(ud_ids, formatted_port.GetName(python_node))
null_node = master.CreateNode(master.GetRoot(), c4d.ID_OPERATOR_OBJECT, x=300, y=100)
null_node[c4d.GV_OBJECT_OBJECT_ID] = null
name_port = null_node.AddPort(c4d.GV_PORT_INPUT, c4d.ID_BASELIST_NAME)
name_port.Connect(formatted_port)
python_node.RemoveUnusedPorts()
def generate_code(ud_ids, output_name):
enum_ids = ""
for i, mode in enumerate(_display_modes):
enum_ids += "{0} = {1}\n".format(mode, i)
for k, v in ud_ids.iteritems():
enum_ids += "{0} = {1}\n".format(k, v)
return NODE_CODE.replace("__ENUM_IDS__", enum_ids).replace("__OUTPUT__", output_name)
def create_object(doc, object_type):
obj = c4d.BaseObject(object_type)
doc.InsertObject(obj)
doc.AddUndo(c4d.UNDO_NEW, obj)
doc.SetActiveObject(obj)
return obj
def main():
null = create_object(doc, c4d.Onull)
ud_ids = create_userdata(null)
create_xpresso(null, ud_ids)
c4d.EventAdd(c4d.EVENT_0)
if __name__=='__main__':
main()