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 #####
23 "author": "Campbell Barton",
24 "blender": (2, 80, 0),
25 "location": "File > Demo Menu",
26 "description": "Demo mode lets you select multiple blend files and loop over them.",
28 "wiki_url": "https://docs.blender.org/manual/en/dev/addons/"
29 "system/demo_mode.html",
30 "support": 'OFFICIAL',
34 # To support reload properly, try to access a package var, if it's there, reload everything
37 if "config" in locals():
38 importlib
.reload(config
)
42 from bpy
.props
import (
51 class DemoModeSetup(bpy
.types
.Operator
):
52 """Create a demo script and optionally execute it"""
53 bl_idname
= "wm.demo_mode_setup"
54 bl_label
= "Demo Mode (Setup)"
55 bl_options
= {'PRESET'}
57 # List of operator properties, the attributes will be assigned
58 # to the class instance from the operator settings before calling.
60 # these are used to create the file list.
61 directory
: StringProperty(
63 description
="Directory used for importing the file",
67 random_order
: BoolProperty(
69 description
="Select files randomly",
77 ('RENDER', "Render", ""),
82 name
="Run Immediately!",
83 description
="Run demo immediately",
88 description
="Run once and exit",
92 # these are mapped directly to the config!
96 anim_cycles
: IntProperty(
98 description
="Number of times to play the animation",
102 anim_time_min
: FloatProperty(
104 description
="Minimum number of seconds to show the animation for "
107 soft_min
=1.0, soft_max
=1000.0,
110 anim_time_max
: FloatProperty(
112 description
="Maximum number of seconds to show the animation for "
113 "(in case the end frame is very high for no reason)",
114 min=0.0, max=100000000.0,
115 soft_min
=1.0, soft_max
=100000000.0,
118 anim_screen_switch
: FloatProperty(
119 name
="Screen Switch",
120 description
="Time between switching screens (in seconds) "
122 min=0.0, max=100000000.0,
123 soft_min
=1.0, soft_max
=60.0,
129 display_render
: FloatProperty(
131 description
="Time to display the rendered image before moving on "
136 anim_render
: BoolProperty(
138 description
="Render entire animation (render mode only)",
142 def execute(self
, context
):
145 keywords
= self
.as_keywords(ignore
=("directory", "random_order", "run", "exit"))
146 cfg_str
, _dirpath
= config
.as_string(
152 text
= bpy
.data
.texts
.get("demo.py")
156 text
= bpy
.data
.texts
.new("demo.py")
157 text
.from_string(cfg_str
)
160 extern_demo_mode_run()
164 def invoke(self
, context
, event
):
165 context
.window_manager
.fileselect_add(self
)
166 return {'RUNNING_MODAL'}
168 def check(self
, context
):
171 def draw(self
, context
):
175 box
.label(text
="Search *.blend recursively")
176 box
.label(text
="Writes: demo.py config text")
178 layout
.prop(self
, "run")
179 layout
.prop(self
, "exit")
181 layout
.label(text
="Generate Settings:")
183 row
.prop(self
, "mode", expand
=True)
184 layout
.prop(self
, "random_order")
189 sub
= layout
.column()
190 sub
.active
= (mode
in {'AUTO', 'PLAY'})
191 sub
.label(text
="Animate Settings:")
192 sub
.prop(self
, "anim_cycles")
193 sub
.prop(self
, "anim_time_min")
194 sub
.prop(self
, "anim_time_max")
195 sub
.prop(self
, "anim_screen_switch")
198 sub
= layout
.column()
199 sub
.active
= (mode
in {'AUTO', 'RENDER'})
200 sub
.label(text
="Render Settings:")
201 sub
.prop(self
, "display_render")
204 class DemoModeRun(bpy
.types
.Operator
):
205 bl_idname
= "wm.demo_mode_run"
206 bl_label
= "Demo Mode (Start)"
208 def execute(self
, context
):
209 if extern_demo_mode_run():
212 self
.report({'ERROR'}, "Cant load demo.py config, run: File -> Demo Mode (Setup)")
216 # --- call demo_mode.py funcs
217 def extern_demo_mode_run():
218 # this accesses demo_mode.py which is kept standalone
219 # and can be run direct.
220 from . import demo_mode
221 if demo_mode
.load_config():
222 demo_mode
.demo_mode_load_file() # kick starts the modal operator
228 def extern_demo_mode_register():
229 # this accesses demo_mode.py which is kept standalone
230 # and can be run direct.
231 from . import demo_mode
235 def extern_demo_mode_unregister():
236 # this accesses demo_mode.py which is kept standalone
237 # and can be run direct.
238 from . import demo_mode
239 demo_mode
.unregister()
244 def menu_func(self
, context
):
246 layout
.operator(DemoModeSetup
.bl_idname
, icon
='PREFERENCES')
247 layout
.operator(DemoModeRun
.bl_idname
, icon
='PLAY')
257 from bpy
.utils
import register_class
261 bpy
.types
.TOPBAR_MT_file
.prepend(menu_func
)
263 extern_demo_mode_register()
267 from bpy
.utils
import unregister_class
269 unregister_class(cls
)
271 bpy
.types
.TOPBAR_MT_file
.remove(menu_func
)
273 extern_demo_mode_unregister()
275 if __name__
== "__main__":