Render Path List

First addon. Render output file path list.

render_path_list.py


bl_info = {
    "name": "Render Path List",
    "author": "Boolnori",
    "version": (0, 0, 1),
    "blender": (2, 78, 0),
    "location": "Render Settings > Render Path List",
    "description": "Render Path List (file path, frame start, frame end)",
    "warning": "",
    "wiki_url": "",
    "category": "Render",
    }


import bpy


from bpy.types import (
    Operator,
    Panel,
    UIList,
    PropertyGroup,
)


from bpy.props import (
    StringProperty,
    IntProperty,
    CollectionProperty,
    PointerProperty,
)


#Property
class PathListSet(bpy.types.PropertyGroup):
    name = StringProperty(name = "Path Name", description="render filepath")
    render_file_format = StringProperty(name = "render file format", description="render file format")
    path_frame_start = IntProperty(name = "Start Number")
    path_frame_end = IntProperty(name = "End Number")


class ActivePathSet(bpy.types.PropertyGroup):
    active_path_idx = IntProperty(
        name="Index",
        description="Index of the currently active path list",
        default=0
    )


    active_path_frame_start = IntProperty(
        name="Start",
        description="Start frame of the active path playback/rendering range",
        default = 1
    )


    active_path_frame_end = IntProperty(
        name="End",
        description="End frame of the active path playback/rendering range",
        default= 1
    )
    
    prev_path_idx = IntProperty(
        name="Previous Index",
        description="Index of the Previous active path list",
        default=0
    )




#Panel
class RenderPathList(bpy.types.UIList):
    def draw_item(self, context, layout, data, set, icon, active_data, active_propname, index):
        layout.prop(set, "name", text="", icon='FILE_FOLDER', emboss=False)




class RenderPathListPanel(bpy.types.Panel):
    """Creates a Panel in the Render properties window"""
    bl_label = "Render Path List"
    bl_idname = "Scene_Render_File_Path_list"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "render"
    
    def draw(self, context):
        scene = context.scene
        apSetData = scene.actpath_set
        
        layout = self.layout
        row = layout.row()
        rows=2


        row.template_list("RenderPathList", "", scene, "path_list", apSetData, "active_path_idx",rows=rows)
        
        row = layout.row()


        sub = row.row(align=True)
        sub.operator("render.path_add", icon='ZOOMIN', text="")
        sub.operator("render.path_remove", icon='ZOOMOUT', text="")
        sub.operator("render.output_filepath_set", text="Set")
        sub.operator("render.play_rendered_animation", text="Play")
        sub.operator("render.path_list_delete_all", icon='X', text="")
        
        row = layout.row()
        sub2 = row.row(align=True)
        sub2.prop(apSetData, "active_path_frame_start", expand=True)
        sub2.prop(apSetData, "active_path_frame_end", expand=True)
        
        if scene.path_list.items() != []:
            frameRagneLimit(self, context)
            apSetData.prev_path_idx = apSetData.active_path_idx
        else:
            sub2.enabled = False
        
# Operators
class RENDER_OT_path_list_delete_all(Operator):
    bl_idname = "render.path_list_delete_all"
    bl_label = "Delete All List"
    bl_description = "Deletes All Render Path List"
    bl_options = {'UNDO', 'REGISTER'}


    def execute(self, context):
        scene = context.scene
        apSetData = scene.actpath_set
        
        scene.path_list.clear()
        apSetData.active_path_idx = 0
        apSetData.active_path_frame_start = 1
        apSetData.active_path_frame_end = 1
        apSetData.prev_path_idx = 0
        
        return {'FINISHED'}


class RENDER_OT_path_add(Operator):
    bl_idname = "render.path_add"
    bl_label = "Add Render Output Filepath"
    bl_description = "Current Output Filepath Add(The Same Path Overwirte)"
    bl_options = {'UNDO', 'REGISTER'}


    def execute(self, context):
        scene = context.scene
        apSetData = scene.actpath_set
        
        curRenderFilePath = scene.render.filepath
        curPathFrameStart = scene.frame_start
        curPathFrameEnd = scene.frame_end
            
        new_path = scene.path_list.add()
        new_path.name = curRenderFilePath
        new_path.path_frame_start = curPathFrameStart
        new_path.path_frame_end = curPathFrameEnd
    
        next_idx =len(scene.path_list.items())
        apSetData.active_path_idx = next_idx - 1
    
        apSetData.active_path_frame_start = scene.path_list[apSetData.active_path_idx].path_frame_start
        apSetData.active_path_frame_end = scene.path_list[apSetData.active_path_idx].path_frame_end
    
        return {'FINISHED'}




class RENDER_OT_path_remove(Operator):
    bl_idname = "render.path_remove"
    bl_label = "Delete Render Output Filepath"
    bl_description = "Delete Render Output Filepath"
    bl_options = {'UNDO', 'REGISTER'}


    def execute(self, context):
        scene = context.scene
        apSetData = scene.actpath_set
        
        scene.path_list.remove(apSetData.active_path_idx)
        
        pathListNums = len(scene.path_list)
        
        if scene.path_list.items()!=[]:
            if apSetData.active_path_idx >= pathListNums:
                apSetData.active_path_idx = apSetData.active_path_idx - 1
        
            apSetData.active_path_frame_start = scene.path_list[apSetData.active_path_idx].path_frame_start
            apSetData.active_path_frame_end = scene.path_list[apSetData.active_path_idx].path_frame_end


        return {'FINISHED'}




class RENDER_OT_output_filepath_set(Operator):
    bl_idname = "render.output_filepath_set"
    bl_label = "Render Output Filepath Set"
    bl_description = "Render Output Filepath Set"
    bl_options = {'UNDO', 'REGISTER'}


    def execute(self, context):
        scene = context.scene
        apSetData = scene.actpath_set
        
        if scene.path_list.items()!=[]:
            selPath = scene.path_list[apSetData.active_path_idx]
            
            scene.render.filepath = selPath.name
            scene.frame_start = selPath.path_frame_start
            scene.frame_end = selPath.path_frame_end
        else:
            print("Path List Empty")
            
        return {'FINISHED'}




class RENDER_OT_play_rendered_animation(Operator):
    bl_idname = "render.play_rendered_animation"
    bl_label = "Play Rendered Animation"
    bl_description = "Play Rendered Animation"
    bl_options = {'UNDO', 'REGISTER'}


    def execute(self, context):
        scene = context.scene
        apSetData = scene.actpath_set
        
        if scene.path_list.items()!=[]:
            selPath = scene.path_list[apSetData.active_path_idx]
            
            curRenderPath = scene.render.filepath
            curPathFrameStart = scene.frame_start
            curPathFrameEnd = scene.frame_end
            
            scene.render.filepath = selPath.name
            scene.frame_start = selPath.path_frame_start
            scene.frame_end = selPath.path_frame_end
            
            bpy.ops.render.play_rendered_anim()
            
            scene.render.filepath = curRenderPath
            scene.frame_start = curPathFrameStart
            scene.frame_end = curPathFrameEnd
            print("play")
        else:
            print("Path List Empty")


        
        return {'FINISHED'}




def frameRagneLimit(self, context):
    scene = context.scene
    apSetData = scene.actpath_set


    if apSetData.prev_path_idx != apSetData.active_path_idx:
        apSetData.active_path_frame_start = scene.path_list[apSetData.active_path_idx].path_frame_start
        apSetData.active_path_frame_end = scene.path_list[apSetData.active_path_idx].path_frame_end
    else:
        curpath_frame_start = scene.path_list[apSetData.active_path_idx].path_frame_start
        curpath_frame_end = scene.path_list[apSetData.active_path_idx].path_frame_end


        if curpath_frame_start != apSetData.active_path_frame_start:
            if apSetData.active_path_frame_start < 0:
                apSetData.active_path_frame_start = 0
            elif apSetData.active_path_frame_start > apSetData.active_path_frame_end:
                apSetData.active_path_frame_end = apSetData.active_path_frame_start
        elif curpath_frame_end != apSetData.active_path_frame_end:
            if apSetData.active_path_frame_end < 0:
                apSetData.active_path_frame_end = 0
            if apSetData.active_path_frame_end < apSetData.active_path_frame_start:
                apSetData.active_path_frame_start = apSetData.active_path_frame_end
            
        scene.path_list[apSetData.active_path_idx].path_frame_start = apSetData.active_path_frame_start
        scene.path_list[apSetData.active_path_idx].path_frame_end = apSetData.active_path_frame_end        




# Registry
classes = (
    PathListSet,
    ActivePathSet,
    RenderPathList,
    RenderPathListPanel,
    RENDER_OT_path_list_delete_all,
    RENDER_OT_path_add,
    RENDER_OT_path_remove,
    RENDER_OT_output_filepath_set,
    RENDER_OT_play_rendered_animation,
)




def register():
    for cls in classes:
        bpy.utils.register_class(cls)


    bpy.types.Scene.path_list = CollectionProperty(
        type=PathListSet,
        name="Path List",
        description="Render File Path List",
    )


    bpy.types.Scene.actpath_set = PointerProperty(
        type=ActivePathSet,
        name = "Active Path Info",
        description="Current Selected Path infomation",
    )
    


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)


    del bpy.types.Scene.path_list
    del bpy.types.Scene.actpath_set




if __name__ == "__main__":
    register()



Thank you!