From 478309859bab63dd28a80202c3df6e180b228524 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 19 Dec 2011 14:19:23 +0000 Subject: Moving render_copy_settings from contrib to trunk. [[Split portion of a mixed commit.]] --- render_copy_settings/__init__.py | 155 ++++++++++++++++++++++++++++++ render_copy_settings/operator.py | 198 +++++++++++++++++++++++++++++++++++++++ render_copy_settings/panel.py | 67 +++++++++++++ render_copy_settings/presets.py | 46 +++++++++ 4 files changed, 466 insertions(+) create mode 100644 render_copy_settings/__init__.py create mode 100644 render_copy_settings/operator.py create mode 100644 render_copy_settings/panel.py create mode 100644 render_copy_settings/presets.py (limited to 'render_copy_settings') diff --git a/render_copy_settings/__init__.py b/render_copy_settings/__init__.py new file mode 100644 index 00000000..ee02f38c --- /dev/null +++ b/render_copy_settings/__init__.py @@ -0,0 +1,155 @@ +# ##### 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 ##### + +# + +# ##### CHANGELOG ##### +# +# 0.0.1 +# Initial release. +# +# 0.0.2 +# Updates to follow Blender API: +# * bl_addon_info renamed in bl_info! +# * adding bpy.utils.(un)register_module calls. +# Also, in standard import, using “from . import …” now. +# +# 0.1.0 +# Renamed in “Render Copy Settings”. +# Huge changes: +# * It is now possible to individually copy each render setting. +# * It is now possible to individually select each affected scene, and then filter them out +# even further with a regex. +# WARNING: this addon now needs a Blender patched with the ui_template_list diff, else it won’t +# be fully functional… +# +# 0.1.1 +# Minor changes: +# * PEP8 compliant. +# * Moved to contrib… +# WARNING: this addon now needs a Blender patched with the ui_template_list diff, else it won’t +# be fully functional (even though working)… +# +# 0.1.2 +# Minor changes: +# * Updated accordingly to the changes in enhanced ui_template_list proposal. +# WARNING: this addon now needs a Blender patched with the ui_template_list diff, else it won’t +# be fully functional (even though working)… +# +# 0.1.3 +# Minor changes: +# * Fixed a small bug that was disabling the whole UI when entering a filtering regex +# matching no scene. +# WARNING: this addon now needs a Blender patched with the ui_template_list diff, else it won’t +# be fully functional (even though working)… +# +# ##### END OF CHANGELOG ##### + +bl_info = { + "name": "Copy Settings", + "author": "Bastien Montagne", + "version": (0, 1, 4), + "blender": (2, 6, 1), + "api": 42648, + "location": "Render buttons (Properties window)", + "description": "Allows to copy a selection of render settings from current scene to others.", + "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ + "Scripts/Render/Copy Settings", + "tracker_url": "http://projects.blender.org/tracker/index.php?func=detail&aid=25832", + "category": "Render"} + + +if "bpy" in locals(): + import imp + imp.reload(operator) + imp.reload(panel) + +else: + from . import operator, panel + + +import bpy +from bpy.props import StringProperty, BoolProperty, IntProperty, CollectionProperty + + +#################################################################################################### +# Global properties for the script, for UI (as there’s no way to let them in the operator…). +#################################################################################################### + +class RenderCopySettingsScene(bpy.types.PropertyGroup): + allowed = BoolProperty(default=True) + + # A string of identifiers (colon delimited) which property’s controls should be displayed + # in a template_list. + template_list_controls = StringProperty(default="allowed", options={"HIDDEN"}) + + +class RenderCopySettingsSetting(bpy.types.PropertyGroup): + strid = StringProperty(default="") + copy = BoolProperty(default=False) + + # A string of identifiers (colon delimited) which property’s controls should be displayed + # in a template_list. + template_list_controls = StringProperty(default="copy", options={"HIDDEN"}) + + +class RenderCopySettings(bpy.types.PropertyGroup): + # XXX: The consistency of this collection is delegated to the UI code. + # It should only contain one element for each render setting. + affected_settings = CollectionProperty(type=RenderCopySettingsSetting, + name="Affected Settings", + description="The list of all available render settings") + # XXX Unused, but needed for template_list… + aff_sett_idx = IntProperty() + + # XXX: The consistency of this collection is delegated to the UI code. + # It should only contain one element for each scene. + allowed_scenes = CollectionProperty(type=RenderCopySettingsScene, + name="Allowed Scenes", + description="The list all scenes in the file") + # XXX Unused, but needed for template_list… + allw_scenes_idx = IntProperty() + + filter_scene = StringProperty(name="Filter Scene", + description="Regex to only affect scenes which name matches it", + default="") + + +def register(): + # Register properties. + bpy.utils.register_class(RenderCopySettingsScene) + bpy.utils.register_class(RenderCopySettingsSetting) + bpy.utils.register_class(RenderCopySettings) + bpy.types.Scene.render_copy_settings = \ + bpy.props.PointerProperty(type=RenderCopySettings) + + bpy.utils.register_module(__name__) + + +def unregister(): + # Unregister properties. + bpy.utils.unregister_class(RenderCopySettingsScene) + bpy.utils.unregister_class(RenderCopySettingsSetting) + bpy.utils.unregister_class(RenderCopySettings) + del bpy.types.Scene.render_copy_settings + + bpy.utils.unregister_module(__name__) + + +if __name__ == "__main__": + register() diff --git a/render_copy_settings/operator.py b/render_copy_settings/operator.py new file mode 100644 index 00000000..830ce4a7 --- /dev/null +++ b/render_copy_settings/operator.py @@ -0,0 +1,198 @@ +# ##### 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 ##### + +# + +import bpy +from . import presets + +# These operators are only defined because it seems impossible to directly edit properties from +# UI code… + + +# A sorting func for collections (working in-place). +# XXX Not optimized at all… +# XXX If some items in the collection do not have the sortkey property, they are just ignored… +def collection_property_sort(collection, sortkey, start_idx=0): + while start_idx + 1 < len(collection): + while not hasattr(collection[start_idx], sortkey): + start_idx += 1 + if start_idx + 1 >= len(collection): + return collection + min_idx = start_idx + min_prop = collection[start_idx] + for i, prop in enumerate(collection[start_idx + 1:]): + if not hasattr(prop, sortkey): + continue + if getattr(prop, sortkey) < getattr(min_prop, sortkey): + min_prop = prop + min_idx = i + start_idx + 1 + collection.move(min_idx, start_idx) + start_idx += 1 + return collection + + +class RenderCopySettingsPrepare(bpy.types.Operator): + ''' + Prepare internal data for render_copy_settings (gathering all existing render settings, + and scenes) + ''' + bl_idname = "scene.render_copy_settings_prepare" + bl_label = "Render: Copy Settings Prepare" + bl_option = {'REGISTER'} + + @classmethod + def poll(cls, context): + return context.scene != None + + def execute(self, context): + cp_sett = context.scene.render_copy_settings + + # Get all available render settings, and update accordingly affected_settings… + props = {} + for prop in context.scene.render.bl_rna.properties: + if prop.identifier in {'rna_type'}: + continue + if prop.is_readonly: + continue + props[prop.identifier] = prop.name + corr = 0 + for i, sett in enumerate(cp_sett.affected_settings): + if sett.strid not in props: + cp_sett.affected_settings.remove(i-corr) + corr += 1 + else: + del props[sett.strid] + for strid, name in props.items(): + sett = cp_sett.affected_settings.add() + sett.name = "{} [{}]".format(name, strid) + sett.strid = strid + collection_property_sort(cp_sett.affected_settings, "name") + + # Get all available scenes, and update accordingly allowed_scenes… + regex = None + if cp_sett.filter_scene: + try: + import re + try: + regex = re.compile(cp_sett.filter_scene) + except Exception as e: + self.report('ERROR_INVALID_INPUT', "The filter-scene regex " \ + "did not compile:\n (%s)." % str(e)) + return {'CANCELLED'} + except: + regex = None + self.report('WARNING', "Unable to import the re module. Regex " \ + "scene filtering will be disabled!") + scenes = set() + for scene in bpy.data.scenes: + if scene == bpy.context.scene: # Exclude current scene! + continue + if regex: # If a valid filtering regex, only keep scenes matching it. + if regex.match(scene.name): + scenes.add(scene.name) + else: + scenes.add(scene.name) + for i, scene in enumerate(cp_sett.allowed_scenes): + if scene.name not in scenes: + cp_sett.allowed_scenes.remove(i) + else: + scenes.remove(scene.name) + for scene in scenes: + sett = cp_sett.allowed_scenes.add() + sett.name = scene + collection_property_sort(cp_sett.allowed_scenes, "name") + + return {'FINISHED'} + + +from bpy.props import EnumProperty + + +class RenderCopySettingsPreset(bpy.types.Operator): + '''Apply some presets of render settings to copy to other scenes''' + bl_idname = "scene.render_copy_settings_preset" + bl_label = "Render: Copy Settings Preset" + bl_description = "Apply or clear this preset of render settings" + # Enable undo… + bl_option = {'REGISTER', 'UNDO'} + + presets = EnumProperty(items=(p.rna_enum for p in presets.presets), + default=set(), + options={"ENUM_FLAG"}) + + @staticmethod + def process_elements(settings, elts): + setts = [] + val = True + for sett in settings: + if sett.strid in elts: + setts.append(sett) + val = val and sett.copy + for e in setts: + e.copy = not val + + @classmethod + def poll(cls, context): + return context.scene != None + + def execute(self, context): + cp_sett = context.scene.render_copy_settings + for p in presets.presets: + if p.rna_enum[0] in self.presets: + self.process_elements(cp_sett.affected_settings, p.elements) + return {'FINISHED'} + + +# Real interesting stuff… + +def do_copy(context, affected_settings, allowed_scenes): + # Stores render settings from current scene. + p = {sett: getattr(context.scene.render, sett) for sett in affected_settings} + # put it in all other (valid) scenes’ render settings! + for scene in bpy.data.scenes: + # If scene not in allowed scenes, skip. + if scene.name not in allowed_scenes: + continue + # Propagate all affected settings. + for sett, val in p.items(): + setattr(scene.render, sett, val) + + +class RenderCopySettings(bpy.types.Operator): + '''Copy render settings from current scene to others''' + bl_idname = "scene.render_copy_settings" + bl_label = "Render: Copy Settings" + # Enable undo… + bl_option = {'REGISTER', 'UNDO'} + + @classmethod + def poll(cls, context): + return context.scene != None + + def execute(self, context): + regex = None + cp_sett = context.scene.render_copy_settings + affected_settings = set([sett.strid for sett in cp_sett.affected_settings if sett.copy]) + allowed_scenes = set([sce.name for sce in cp_sett.allowed_scenes if sce.allowed]) + do_copy(context, affected_settings=affected_settings, allowed_scenes=allowed_scenes) + return {'FINISHED'} + + +if __name__ == "__main__": + bpy.ops.scene.render_copy_settings() diff --git a/render_copy_settings/panel.py b/render_copy_settings/panel.py new file mode 100644 index 00000000..486f186c --- /dev/null +++ b/render_copy_settings/panel.py @@ -0,0 +1,67 @@ +# ##### 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 ##### + +# + +import bpy +from . import presets + + +class RENDER_PT_copy_settings(bpy.types.Panel): + bl_label = "Copy Settings" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "render" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_RENDER'} + + def draw(self, context): + layout = self.layout + cp_sett = context.scene.render_copy_settings + + layout.operator("scene.render_copy_settings", text="Copy Render Settings") + + # This will update affected_settings/allowed_scenes (as this seems to be impossible + # to do it from here…). + if bpy.ops.scene.render_copy_settings_prepare.poll(): + bpy.ops.scene.render_copy_settings_prepare() + + split = layout.split(0.75) + split.template_list(cp_sett, "affected_settings", cp_sett, "aff_sett_idx", + prop_list="template_list_controls", rows=6) + + col = split.column() + all_set = {sett.strid for sett in cp_sett.affected_settings if sett.copy} + for p in presets.presets: + label = "" + if p.elements & all_set == p.elements: + label = "Clear {}".format(p.ui_name) + else: + label = "Set {}".format(p.ui_name) + col.operator("scene.render_copy_settings_preset", text=label, ).presets = {p.rna_enum[0]} + + layout.prop(cp_sett, "filter_scene") + if len(cp_sett.allowed_scenes): + layout.label("Affected Scenes:") + # XXX Unfortunately, there can only be one template_list per panel… +# layout.template_list(cp_sett, "allowed_scenes", cp_sett, "allw_scenes_idx", rows=5) + col = layout.column_flow(columns=0) + for i, prop in enumerate(cp_sett.allowed_scenes): + col.prop(prop, "allowed", toggle=True, text=prop.name) + else: + layout.label(text="No Affectable Scenes!", icon="ERROR") diff --git a/render_copy_settings/presets.py b/render_copy_settings/presets.py new file mode 100644 index 00000000..7ba6ff4e --- /dev/null +++ b/render_copy_settings/presets.py @@ -0,0 +1,46 @@ +# ##### 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 ##### + +# + +class CopyPreset(object): + def __init__(self, ui_name, rna_enum, elements): + self.ui_name = ui_name + self.rna_enum = rna_enum + self.elements = elements + + +presets = (CopyPreset("Resolution", + ("resolution", "Render Resolution", "Render resolution and aspect ratio settings"), + {"resolution_x", "resolution_y", "pixel_aspect_x", "pixel_aspect_y"}), + CopyPreset("Scale", + ("scale", "Render Scale", "The “Render Scale” setting."), + {"resolution_percentage"}), + CopyPreset("OSA", + ("osa", "Render OSA", "The OSA toggle and sample settings."), + {"use_antialiasing", "antialiasing_samples"}), + CopyPreset("Threads", + ("threads", "Render Threads", "The thread mode and number settings."), + {"threads_mode", "threads"}), + CopyPreset("Fields", + ("fields", "Render Fields", "The Fields settings."), + {"use_fields", "field_order", "use_fields_still"}), + CopyPreset("Stamp", + ("stamp", "Render Stamp", "The Stamp toggle."), + {"use_stamp"}) + ) -- cgit v1.2.3