1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
22 This module translates a python like XML representation into XML
23 or simple python blender/ui function calls.
34 <another key="value" />
39 TAG, ARGS, CHILDREN = range(3)
42 class ReturnStore(tuple):
43 def __getitem__(self, key):
46 if type(key) is ReturnStore:
49 if type(key) is tuple:
50 children = self[CHILDREN]
52 raise Exception("Only a single __getitem__ is allowed on the ReturnStore")
57 return tuple.__getitem__(self, key)
60 class FunctionStore(object):
61 def __call__(self, **kwargs):
62 return ReturnStore((self.__class__.__name__, kwargs, []))
65 def tag_vars(tags, module=__name__):
66 return {tag: type(tag, (FunctionStore, ), {"__module__": module})() for tag in tags}
69 def tag_module(mod_name, tags):
71 from types import ModuleType
72 mod = ModuleType(mod_name)
73 sys.modules[mod_name] = mod
74 dict_values = tag_vars(tags, mod_name)
75 mod.__dict__.update(dict_values)
79 def toxml(py_data, indent=" "):
81 if len(py_data) != 1 or type(py_data) != list:
82 raise Exception("Expected a list with one member")
84 def _to_xml(py_item, xml_node=None):
86 xml_node = newdoc.createElement(py_item[TAG])
88 for key, value in py_item[ARGS].items():
89 xml_node.setAttribute(key, str(value))
91 for py_item_child in py_item[CHILDREN]:
92 xml_node.appendChild(_to_xml(py_item_child))
96 def _to_xml_iter(xml_parent, data_ls):
97 for py_item in data_ls:
98 xml_node = newdoc.createElement(py_item[TAG])
101 _to_xml_iter(xml_node, py_item[CHILDREN])
103 import xml.dom.minidom
104 impl = xml.dom.minidom.getDOMImplementation()
105 newdoc = impl.createDocument(None, py_data[0][TAG], None)
107 _to_xml(py_data[0], newdoc.documentElement)
109 return newdoc.documentElement.toprettyxml(indent=" ")
113 def _fromxml_kwargs(xml_node):
115 for key, value in xml_node.attributes.items():
119 def _fromxml(xml_node):
120 py_item = (xml_node.tagName, _fromxml_kwargs(xml_node), [])
121 #_fromxml_iter(py_item, xml_node.childNodes)
122 for xml_node_child in xml_node.childNodes:
123 if xml_node_child.nodeType not in (xml_node_child.TEXT_NODE, xml_node_child.COMMENT_NODE):
124 py_item[CHILDREN].append(_fromxml(xml_node_child))
127 import xml.dom.minidom
128 xml_doc = xml.dom.minidom.parseString(data)
129 return [_fromxml(xml_doc.documentElement)]
132 def topretty_py(py_data, indent=" "):
134 if len(py_data) != 1:
135 raise Exception("Expected a list with one member")
139 def _to_kwargs(kwargs):
140 return ", ".join([("%s=%s" % (key, repr(value))) for key, value in sorted(kwargs.items())])
142 def _topretty(py_item, indent_ctx, last):
143 if py_item[CHILDREN]:
144 lines.append("%s%s(%s) [" % (indent_ctx, py_item[TAG], _to_kwargs(py_item[ARGS])))
145 py_item_last = py_item[CHILDREN][-1]
146 for py_item_child in py_item[CHILDREN]:
147 _topretty(py_item_child, indent_ctx + indent, (py_item_child is py_item_last))
148 lines.append("%s]%s" % (indent_ctx, ("" if last else ",")))
150 lines.append("%s%s(%s)%s" % (indent_ctx, py_item[TAG], _to_kwargs(py_item[ARGS]), ("" if last else ",")))
152 _topretty(py_data[0], "", True)
154 return "\n".join(lines)
156 if __name__ == "__main__":
159 tag_module("bpyml_test", ("ui", "prop", "row", "column", "active", "separator", "split"))
160 from bpyml_test import *
166 prop(data='context.scene.render', property='use_stamp_time', text='Time'),
167 prop(data='context.scene.render', property='use_stamp_date', text='Date'),
168 prop(data='context.scene.render', property='use_stamp_render_time', text='RenderTime'),
169 prop(data='context.scene.render', property='use_stamp_frame', text='Frame'),
170 prop(data='context.scene.render', property='use_stamp_scene', text='Scene'),
171 prop(data='context.scene.render', property='use_stamp_camera', text='Camera'),
172 prop(data='context.scene.render', property='use_stamp_filename', text='Filename'),
173 prop(data='context.scene.render', property='use_stamp_marker', text='Marker'),
174 prop(data='context.scene.render', property='use_stamp_sequencer_strip', text='Seq. Strip')
177 active(expr='context.scene.render.use_stamp'),
178 prop(data='context.scene.render', property='stamp_foreground', slider=True),
179 prop(data='context.scene.render', property='stamp_background', slider=True),
181 prop(data='context.scene.render', property='stamp_font_size', text='Font Size')
184 split(percentage=0.2) [
185 prop(data='context.scene.render', property='use_stamp_note', text='Note'),
187 active(expr='context.scene.render.use_stamp_note'),
188 prop(data='context.scene.render', property='stamp_note_text', text='')
194 xml_data = toxml(draw)
195 print(xml_data) # xml version
197 py_data = fromxml(xml_data)
198 print(py_data) # converted back to py
200 xml_data = toxml(py_data)
201 print(xml_data) # again back to xml
203 py_data = fromxml(xml_data) # pretty python version
204 print(topretty_py(py_data))