python declarative UI
- remove XML testing feature
- add 2 modules: bpyml - generic, bpyml_ui - blender spesific. nothing uses these now.
==bpyml_ui module==
defines BPyML_BaseUI and its draw() function which uses the bpyml member of the class instance self.draw_data & self.draw_header_data.
This way declarative ui is opt-in and easy to use by using BPyML_BaseUI as a mix-in class.
==bpyml module==
This module translates a python like XML representation into XML
or simple python blender/ui function calls.
sometag(arg=10) [
another(),
another(key="value")
]
# converts into ...
<sometag arg="10">
<another/>
<another key="value" />
</sometag>
This commit is contained in:
@@ -30,8 +30,6 @@ import sys as _sys
|
||||
from _bpy import blend_paths
|
||||
from _bpy import script_paths as _bpy_script_paths
|
||||
|
||||
_TEST_XML = _bpy.app.debug
|
||||
|
||||
def _test_import(module_name, loaded_modules):
|
||||
import traceback
|
||||
import time
|
||||
@@ -54,35 +52,6 @@ def _test_import(module_name, loaded_modules):
|
||||
loaded_modules.add(mod.__name__) # should match mod.__name__ too
|
||||
return mod
|
||||
|
||||
if _TEST_XML:
|
||||
# TEST CODE
|
||||
def _test_import_xml(path, f, loaded_modules):
|
||||
import bpy_xml_ui
|
||||
import traceback
|
||||
|
||||
f_full = _os.path.join(path, f)
|
||||
_bpy_types._register_immediate = True
|
||||
try:
|
||||
classes = bpy_xml_ui.load_xml(f_full)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
classes = []
|
||||
_bpy_types._register_immediate = False
|
||||
|
||||
if classes:
|
||||
mod_name = f.split(".")[0]
|
||||
|
||||
# fake module
|
||||
mod = type(traceback)(mod_name)
|
||||
mod.__file__ = f_full
|
||||
for cls in classes:
|
||||
setattr(mod, cls.__name__, cls)
|
||||
|
||||
loaded_modules.add(mod_name)
|
||||
_sys.modules[mod_name] = mod
|
||||
mod.register = lambda: None # quiet errors
|
||||
return mod
|
||||
|
||||
|
||||
def modules_from_path(path, loaded_modules):
|
||||
"""
|
||||
@@ -110,10 +79,6 @@ def modules_from_path(path, loaded_modules):
|
||||
else:
|
||||
mod = None
|
||||
|
||||
if _TEST_XML:
|
||||
if mod is None and f.endswith(".xml"):
|
||||
mod = _test_import_xml(path, f, loaded_modules)
|
||||
|
||||
if mod:
|
||||
modules.append(mod)
|
||||
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
"""
|
||||
This module translates XML into blender/ui function calls.
|
||||
"""
|
||||
|
||||
import xml.dom.minidom
|
||||
import bpy as _bpy
|
||||
|
||||
def parse_rna(prop, value):
|
||||
if prop.type == 'FLOAT':
|
||||
value = float(value)
|
||||
elif prop.type == 'INT':
|
||||
value = int(value)
|
||||
elif prop.type == 'BOOLEAN':
|
||||
if value not in ("true", "false"):
|
||||
raise Exception("invalid bool value: %s", value)
|
||||
value = bool(value == "true")
|
||||
elif prop.type in ('STRING', 'ENUM'):
|
||||
pass
|
||||
elif prop.type == 'POINTER':
|
||||
value = eval("_bpy." + value)
|
||||
else:
|
||||
raise Exception("type not supported %s.%s" % (prop.identifier, prop.type))
|
||||
return value
|
||||
|
||||
def parse_args(base, xml_node):
|
||||
args = {}
|
||||
rna_params = base.bl_rna.functions[xml_node.tagName].parameters
|
||||
for key, value in xml_node.attributes.items():
|
||||
args[key] = parse_rna(rna_params[key], value)
|
||||
return args
|
||||
|
||||
def ui_xml(base, xml_node):
|
||||
name = xml_node.tagName
|
||||
prop = base.bl_rna.properties.get(name)
|
||||
if name in base.bl_rna.properties:
|
||||
attr = xml_node.attributes.get("expr")
|
||||
if attr:
|
||||
value = attr.value
|
||||
value = eval(value, {"context": _bpy.context})
|
||||
setattr(base, name, value)
|
||||
else:
|
||||
attr = xml_node.attributes['value']
|
||||
value = attr.value
|
||||
value = parse_rna(prop, value)
|
||||
setattr(base, name, value)
|
||||
else:
|
||||
func_new = getattr(base, name)
|
||||
kw_args = parse_args(base, xml_node)
|
||||
base_new = func_new(**kw_args) # call blender func
|
||||
if xml_node.hasChildNodes():
|
||||
ui_xml_list(base_new, xml_node.childNodes)
|
||||
|
||||
def ui_xml_list(base, xml_nodes):
|
||||
import bpy
|
||||
for node in xml_nodes:
|
||||
if node.nodeType not in (node.TEXT_NODE, node.COMMENT_NODE):
|
||||
ui_xml(base, node)
|
||||
bpy.N = node
|
||||
|
||||
def test(layout):
|
||||
uixml = xml.dom.minidom.parseString(open("/mnt/test/blender-svn/blender/release/scripts/ui/test.xml", 'r').read())
|
||||
panel = uixml.getElementsByTagName('panel')[0]
|
||||
ui_xml_list(layout, panel.childNodes)
|
||||
|
||||
def load_xml(filepath):
|
||||
classes = []
|
||||
fn = open(filepath, 'r')
|
||||
data = fn.read()
|
||||
uixml = xml.dom.minidom.parseString(data).getElementsByTagName("ui")[0]
|
||||
fn.close()
|
||||
|
||||
def draw_xml(self, context):
|
||||
node = self._xml_node.getElementsByTagName("draw")[0]
|
||||
ui_xml_list(self.layout, node.childNodes)
|
||||
|
||||
def draw_header_xml(self, context):
|
||||
node = self._xml_node.getElementsByTagName("draw_header")[0]
|
||||
ui_xml_list(self.layout, node.childNodes)
|
||||
|
||||
for node in uixml.childNodes:
|
||||
if node.nodeType not in (node.TEXT_NODE, node.COMMENT_NODE):
|
||||
name = node.tagName
|
||||
class_name = node.attributes["identifier"].value
|
||||
|
||||
if name == "panel":
|
||||
class_dict = {
|
||||
"bl_label": node.attributes["label"].value,
|
||||
"bl_region_type": node.attributes["region_type"].value,
|
||||
"bl_space_type": node.attributes["space_type"].value,
|
||||
"bl_context": node.attributes["context"].value,
|
||||
"bl_default_closed": ((node.attributes["default_closed"].value == "true") if "default_closed" in node.attributes else False),
|
||||
|
||||
"draw": draw_xml,
|
||||
"_xml_node": node
|
||||
}
|
||||
|
||||
if node.getElementsByTagName("draw_header"):
|
||||
class_dict["draw_header"] = draw_header_xml
|
||||
|
||||
# will register instantly
|
||||
class_new = type(class_name, (_bpy.types.Panel,), class_dict)
|
||||
|
||||
elif name == "menu":
|
||||
class_dict = {
|
||||
"bl_label": node.attributes["label"].value,
|
||||
|
||||
"draw": draw_xml,
|
||||
"_xml_node": node
|
||||
}
|
||||
|
||||
# will register instantly
|
||||
class_new = type(class_name, (_bpy.types.Menu,), class_dict)
|
||||
|
||||
elif name == "header":
|
||||
class_dict = {
|
||||
"bl_label": node.attributes["label"].value,
|
||||
"bl_space_type": node.attributes["space_type"].value,
|
||||
|
||||
"draw": draw_xml,
|
||||
"_xml_node": node
|
||||
}
|
||||
|
||||
# will register instantly
|
||||
class_new = type(class_name, (_bpy.types.Header,), class_dict)
|
||||
else:
|
||||
raise Exception("invalid id found '%s': expected a value in ('header', 'panel', 'menu)'" % name)
|
||||
|
||||
classes.append(class_new)
|
||||
|
||||
|
||||
return classes
|
||||
204
release/scripts/modules/bpyml.py
Normal file
204
release/scripts/modules/bpyml.py
Normal file
@@ -0,0 +1,204 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
"""
|
||||
This module translates a python like XML representation into XML
|
||||
or simple python blender/ui function calls.
|
||||
|
||||
sometag(arg=10) [
|
||||
another()
|
||||
another(key="value")
|
||||
]
|
||||
|
||||
# converts into ...
|
||||
|
||||
<sometag arg="10">
|
||||
<another/>
|
||||
<another key="value" />
|
||||
</sometag>
|
||||
|
||||
"""
|
||||
|
||||
TAG, ARGS, CHILDREN = range(3)
|
||||
class ReturnStore(tuple):
|
||||
def __getitem__(self, key):
|
||||
|
||||
# single item get's
|
||||
if type(key) is ReturnStore:
|
||||
key = (key, )
|
||||
|
||||
if type(key) is tuple:
|
||||
children = self[CHILDREN]
|
||||
if children:
|
||||
raise Exception("Only a single __getitem__ is allowed on the ReturnStore")
|
||||
else:
|
||||
children[:] = key
|
||||
return self
|
||||
else:
|
||||
return tuple.__getitem__(self, key)
|
||||
|
||||
|
||||
class FunctionStore(object):
|
||||
def __call__(self, **kwargs):
|
||||
return ReturnStore((self.__class__.__name__, kwargs, []))
|
||||
|
||||
|
||||
def tag_vars(tags, module=__name__):
|
||||
return {tag: type(tag, (FunctionStore, ), {"__module__": module})() for tag in tags}
|
||||
|
||||
|
||||
def tag_module(mod_name, tags):
|
||||
import sys
|
||||
from types import ModuleType
|
||||
mod = ModuleType(mod_name)
|
||||
sys.modules[mod_name] = mod
|
||||
dict_values = tag_vars(tags, mod_name)
|
||||
mod.__dict__.update(dict_values)
|
||||
return mod
|
||||
|
||||
|
||||
def toxml(py_data, indent=" "):
|
||||
|
||||
if len(py_data) != 1 or type(py_data) != list:
|
||||
raise Exception("Expected a list with one member")
|
||||
|
||||
def _to_xml(py_item, xml_node=None):
|
||||
if xml_node is None:
|
||||
xml_node = newdoc.createElement(py_item[TAG])
|
||||
|
||||
for key, value in py_item[ARGS].items():
|
||||
xml_node.setAttribute(key, str(value))
|
||||
|
||||
for py_item_child in py_item[CHILDREN]:
|
||||
xml_node.appendChild(_to_xml(py_item_child))
|
||||
|
||||
return xml_node
|
||||
|
||||
def _to_xml_iter(xml_parent, data_ls):
|
||||
for py_item in data_ls:
|
||||
xml_node = newdoc.createElement(py_item[TAG])
|
||||
|
||||
|
||||
# ok if its empty
|
||||
_to_xml_iter(xml_node, py_item[CHILDREN])
|
||||
|
||||
import xml.dom.minidom
|
||||
impl = xml.dom.minidom.getDOMImplementation()
|
||||
newdoc = impl.createDocument(None, py_data[0][TAG], None)
|
||||
|
||||
_to_xml(py_data[0], newdoc.documentElement)
|
||||
|
||||
return newdoc.documentElement.toprettyxml(indent=" ")
|
||||
|
||||
|
||||
def fromxml(data):
|
||||
def _fromxml_kwargs(xml_node):
|
||||
kwargs = {}
|
||||
for key, value in xml_node.attributes.items():
|
||||
kwargs[key] = value
|
||||
return kwargs
|
||||
|
||||
|
||||
def _fromxml(xml_node):
|
||||
py_item = (xml_node.tagName, _fromxml_kwargs(xml_node), [])
|
||||
#_fromxml_iter(py_item, xml_node.childNodes)
|
||||
for xml_node_child in xml_node.childNodes:
|
||||
if xml_node_child.nodeType not in (xml_node_child.TEXT_NODE, xml_node_child.COMMENT_NODE):
|
||||
py_item[CHILDREN].append(_fromxml(xml_node_child))
|
||||
return py_item
|
||||
|
||||
import xml.dom.minidom
|
||||
xml_doc = xml.dom.minidom.parseString(data)
|
||||
return [_fromxml(xml_doc.documentElement)]
|
||||
|
||||
|
||||
def topretty_py(py_data, indent=" "):
|
||||
|
||||
if len(py_data) != 1:
|
||||
raise Exception("Expected a list with one member")
|
||||
|
||||
lines = []
|
||||
|
||||
def _to_kwargs(kwargs):
|
||||
return ", ".join([("%s=%s" % (key, repr(value))) for key, value in sorted(kwargs.items())])
|
||||
|
||||
def _topretty(py_item, indent_ctx, last):
|
||||
if py_item[CHILDREN]:
|
||||
lines.append("%s%s(%s) [" % (indent_ctx, py_item[TAG], _to_kwargs(py_item[ARGS])))
|
||||
py_item_last = py_item[CHILDREN][-1]
|
||||
for py_item_child in py_item[CHILDREN]:
|
||||
_topretty(py_item_child, indent_ctx + indent, (py_item_child is py_item_last))
|
||||
lines.append("%s]%s" % (indent_ctx, ("" if last else ",")))
|
||||
else:
|
||||
lines.append("%s%s(%s)%s" % (indent_ctx, py_item[TAG], _to_kwargs(py_item[ARGS]), ("" if last else ",")))
|
||||
|
||||
_topretty(py_data[0], "", True)
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# testing code.
|
||||
|
||||
tag_module("bpyml_test", ("ui", "prop", "row", "column", "active", "separator", "split"))
|
||||
from bpyml_test import *
|
||||
|
||||
draw = [
|
||||
ui() [
|
||||
split() [
|
||||
column() [
|
||||
prop(data='context.scene.render', property='stamp_time', text='Time'),
|
||||
prop(data='context.scene.render', property='stamp_date', text='Date'),
|
||||
prop(data='context.scene.render', property='stamp_render_time', text='RenderTime'),
|
||||
prop(data='context.scene.render', property='stamp_frame', text='Frame'),
|
||||
prop(data='context.scene.render', property='stamp_scene', text='Scene'),
|
||||
prop(data='context.scene.render', property='stamp_camera', text='Camera'),
|
||||
prop(data='context.scene.render', property='stamp_filename', text='Filename'),
|
||||
prop(data='context.scene.render', property='stamp_marker', text='Marker'),
|
||||
prop(data='context.scene.render', property='stamp_sequencer_strip', text='Seq. Strip')
|
||||
],
|
||||
column() [
|
||||
active(expr='context.scene.render.render_stamp'),
|
||||
prop(data='context.scene.render', property='stamp_foreground', slider=True),
|
||||
prop(data='context.scene.render', property='stamp_background', slider=True),
|
||||
separator(),
|
||||
prop(data='context.scene.render', property='stamp_font_size', text='Font Size')
|
||||
]
|
||||
],
|
||||
split(percentage=0.2) [
|
||||
prop(data='context.scene.render', property='stamp_note', text='Note'),
|
||||
row() [
|
||||
active(expr='context.scene.render.stamp_note'),
|
||||
prop(data='context.scene.render', property='stamp_note_text', text='')
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
xml_data = toxml(draw)
|
||||
print(xml_data) # xml version
|
||||
|
||||
py_data = fromxml(xml_data)
|
||||
print(py_data) # converted back to py
|
||||
|
||||
xml_data = toxml(py_data)
|
||||
print(xml_data) # again back to xml
|
||||
|
||||
py_data = fromxml(xml_data) # pretty python version
|
||||
print(topretty_py(py_data))
|
||||
100
release/scripts/modules/bpyml_ui.py
Normal file
100
release/scripts/modules/bpyml_ui.py
Normal file
@@ -0,0 +1,100 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
|
||||
import bpy as _bpy
|
||||
import bpyml
|
||||
from bpyml import TAG, ARGS, CHILDREN
|
||||
from types import ModuleType
|
||||
|
||||
_uilayout_rna = _bpy.types.UILayout.bl_rna
|
||||
|
||||
_uilayout_tags = ["ui"] + \
|
||||
_uilayout_rna.properties.keys() + \
|
||||
_uilayout_rna.functions.keys()
|
||||
|
||||
# these need to be imported directly
|
||||
# >>> from bpyml_ui.locals import *
|
||||
locals = bpyml.tag_module("%s.locals" % __name__ , _uilayout_tags)
|
||||
|
||||
|
||||
def _parse_rna(prop, value):
|
||||
if prop.type == 'FLOAT':
|
||||
value = float(value)
|
||||
elif prop.type == 'INT':
|
||||
value = int(value)
|
||||
elif prop.type == 'BOOLEAN':
|
||||
if value in (True, False):
|
||||
pass
|
||||
else:
|
||||
if value not in ("True", "False"):
|
||||
raise Exception("invalid bool value: %s" % value)
|
||||
value = bool(value == "True")
|
||||
elif prop.type in ('STRING', 'ENUM'):
|
||||
pass
|
||||
elif prop.type == 'POINTER':
|
||||
value = eval("_bpy." + value)
|
||||
else:
|
||||
raise Exception("type not supported %s.%s" % (prop.identifier, prop.type))
|
||||
return value
|
||||
|
||||
|
||||
def _parse_rna_args(base, py_node):
|
||||
rna_params = base.bl_rna.functions[py_node[TAG]].parameters
|
||||
args = {}
|
||||
for key, value in py_node[ARGS].items():
|
||||
args[key] = _parse_rna(rna_params[key], value)
|
||||
return args
|
||||
|
||||
|
||||
def _call_recursive(context, base, py_node):
|
||||
prop = base.bl_rna.properties.get(py_node[TAG])
|
||||
if py_node[TAG] in base.bl_rna.properties:
|
||||
value = py_node[ARGS].get("expr")
|
||||
if value:
|
||||
value = eval(value, {"context": _bpy.context})
|
||||
setattr(base, py_node[TAG], value)
|
||||
else:
|
||||
value = py_node[ARGS]['value'] # have to have this
|
||||
setattr(base, name, value)
|
||||
else:
|
||||
args = _parse_rna_args(base, py_node)
|
||||
func_new = getattr(base, py_node[TAG])
|
||||
base_new = func_new(**args) # call blender func
|
||||
if base_new is not None:
|
||||
for py_node_child in py_node[CHILDREN]:
|
||||
_call_recursive(context, base_new, py_node_child)
|
||||
|
||||
|
||||
class BPyML_BaseUI():
|
||||
'''
|
||||
This is a mix-in class that defines a draw function
|
||||
which checks for draw_data
|
||||
'''
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
for py_node in self.draw_data[CHILDREN]:
|
||||
_call_recursive(context, layout, py_node)
|
||||
|
||||
def draw_header(self, context):
|
||||
layout = self.layout
|
||||
for py_node in self.draw_header_data[CHILDREN]:
|
||||
_call_recursive(context, layout, py_node)
|
||||
@@ -1,79 +0,0 @@
|
||||
<ui>
|
||||
<panel identifier="RENDER_PT_stamp_test" label="Stamp (XML)" space_type="PROPERTIES" region_type="WINDOW" context="render" default_closed="true">
|
||||
<draw_header>
|
||||
<prop data="context.scene.render" property="render_stamp" text=""/>
|
||||
</draw_header>
|
||||
|
||||
<draw>
|
||||
<split>
|
||||
<column>
|
||||
<prop data="context.scene.render" property="stamp_time" text="Time"/>
|
||||
<prop data="context.scene.render" property="stamp_date" text="Date"/>
|
||||
<prop data="context.scene.render" property="stamp_render_time" text="RenderTime"/>
|
||||
<prop data="context.scene.render" property="stamp_frame" text="Frame"/>
|
||||
<prop data="context.scene.render" property="stamp_scene" text="Scene"/>
|
||||
<prop data="context.scene.render" property="stamp_camera" text="Camera"/>
|
||||
<prop data="context.scene.render" property="stamp_filename" text="Filename"/>
|
||||
<prop data="context.scene.render" property="stamp_marker" text="Marker"/>
|
||||
<prop data="context.scene.render" property="stamp_sequencer_strip" text="Seq. Strip"/>
|
||||
</column>
|
||||
<column>
|
||||
<active expr="context.scene.render.render_stamp"/>
|
||||
<prop data="context.scene.render" property="stamp_foreground" slider="true"/>
|
||||
<prop data="context.scene.render" property="stamp_background" slider="true"/>
|
||||
<separator/>
|
||||
<prop data="context.scene.render" property="stamp_font_size" text="Font Size"/>
|
||||
</column>
|
||||
</split>
|
||||
<split percentage="0.2">
|
||||
<prop data="context.scene.render" property="stamp_note" text="Note"/>
|
||||
<row>
|
||||
<active expr="context.scene.render.stamp_note"/>
|
||||
<prop data="context.scene.render" property="stamp_note_text" text=""/>
|
||||
</row>
|
||||
</split>
|
||||
</draw>
|
||||
</panel>
|
||||
|
||||
<panel identifier="RENDER_PT_dimensions_test" label="Dimensions (XML)" space_type="PROPERTIES" region_type="WINDOW" context="render">
|
||||
<draw>
|
||||
<row align="true">
|
||||
<menu menu="RENDER_MT_presets"/>
|
||||
<operator operator="render.preset_add" text="" icon="ZOOMIN"/>
|
||||
</row>
|
||||
<split>
|
||||
<column>
|
||||
<column align="true">
|
||||
<label text="Resolution:"/>
|
||||
<prop data="context.scene.render" property="resolution_x" text="X"/>
|
||||
<prop data="context.scene.render" property="resolution_y" text="Y"/>
|
||||
<prop data="context.scene.render" property="resolution_percentage" text=""/>
|
||||
|
||||
<label text="Aspect Ratio:"/>
|
||||
<prop data="context.scene.render" property="pixel_aspect_x" text="X"/>
|
||||
<prop data="context.scene.render" property="pixel_aspect_y" text="Y"/>
|
||||
</column>
|
||||
<row>
|
||||
<prop data="context.scene.render" property="use_border" text="Border"/>
|
||||
<row>
|
||||
<active expr="context.scene.render.use_border"/>
|
||||
<prop data="context.scene.render" property="crop_to_border" text="Crop"/>
|
||||
</row>
|
||||
</row>
|
||||
</column>
|
||||
<column>
|
||||
<column align="true">
|
||||
<label text="Frame Range:"/>
|
||||
<prop data="context.scene" property="frame_start" text="Start"/>
|
||||
<prop data="context.scene" property="frame_end" text="End"/>
|
||||
<prop data="context.scene" property="frame_step" text="Step"/>
|
||||
|
||||
<label text="Frame Rate:"/>
|
||||
<prop data="context.scene.render" property="fps"/>
|
||||
<prop data="context.scene.render" property="fps_base" text="/"/>
|
||||
</column>
|
||||
</column>
|
||||
</split>
|
||||
</draw>
|
||||
</panel>
|
||||
</ui>
|
||||
@@ -526,7 +526,7 @@ static void rna_def_histogram(BlenderRNA *brna)
|
||||
PropertyRNA *prop;
|
||||
|
||||
static EnumPropertyItem prop_mode_items[] = {
|
||||
{HISTO_MODE_LUMA, "Luma", ICON_COLOR, "Luma", ""},
|
||||
{HISTO_MODE_LUMA, "LUMA", ICON_COLOR, "Luma", ""},
|
||||
{HISTO_MODE_RGB, "RGB", ICON_COLOR, "Red Green Blue", ""},
|
||||
{HISTO_MODE_R, "R", ICON_COLOR, "Red", ""},
|
||||
{HISTO_MODE_G, "G", ICON_COLOR, "Green", ""},
|
||||
|
||||
@@ -257,12 +257,12 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna)
|
||||
prop= RNA_def_property(srna, "start_time", PROP_FLOAT, PROP_TIME);
|
||||
RNA_def_property_float_sdna(prop, NULL, "animStart");
|
||||
RNA_def_property_range(prop, 0, 100);
|
||||
RNA_def_property_ui_text(prop, "Start Time", "Simulation time of the first blender frame");
|
||||
RNA_def_property_ui_text(prop, "Start Time", "Simulation time of the first blender frame (in seconds)");
|
||||
|
||||
prop= RNA_def_property(srna, "end_time", PROP_FLOAT, PROP_TIME);
|
||||
RNA_def_property_float_sdna(prop, NULL, "animEnd");
|
||||
RNA_def_property_range(prop, 0, 100);
|
||||
RNA_def_property_ui_text(prop, "End Time", "Simulation time of the last blender frame");
|
||||
RNA_def_property_ui_text(prop, "End Time", "Simulation time of the last blender frame (in seconds)");
|
||||
|
||||
prop= RNA_def_property(srna, "real_world_size", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "realsize");
|
||||
|
||||
Reference in New Issue
Block a user