modified fix for commits r33811, 33812.
[blender.git] / release / scripts / op / presets.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
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.
7 #
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.
12 #
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.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20
21 import bpy
22 import os
23
24
25 class AddPresetBase():
26     '''Base preset class, only for subclassing
27     subclasses must define
28      - preset_values
29      - preset_subdir '''
30     # bl_idname = "script.preset_base_add"
31     # bl_label = "Add a Python Preset"
32     bl_options = {'REGISTER'} # only because invoke_props_popup requires.
33
34     name = bpy.props.StringProperty(name="Name", description="Name of the preset, used to make the path name", maxlen=64, default="")
35     remove_active = bpy.props.BoolProperty(default=False, options={'HIDDEN'})
36
37     @staticmethod
38     def as_filename(name):  # could reuse for other presets
39         for char in " !@#$%^&*(){}:\";'[]<>,.\\/?":
40             name = name.replace(char, '_')
41         return name.lower().strip()
42
43     def execute(self, context):
44         import os
45         
46         if hasattr(self, "pre_cb"):
47             self.pre_cb(context)
48         
49         preset_menu_class = getattr(bpy.types, self.preset_menu)
50
51         if not self.remove_active:        
52
53             if not self.name:
54                 return {'FINISHED'}
55
56             filename = self.as_filename(self.name)
57
58             target_path = bpy.utils.user_resource('SCRIPTS', os.path.join("presets", self.preset_subdir), create=True)
59
60             if not target_path:
61                 self.report({'WARNING'}, "Failed to create presets path")
62                 return {'CANCELLED'}
63
64             filepath = os.path.join(target_path, filename) + ".py"
65             
66             if hasattr(self, "add"):
67                 self.add(context, filepath)
68             else:
69                 file_preset = open(filepath, 'w')
70                 file_preset.write("import bpy\n")
71
72                 if hasattr(self, "preset_defines"):
73                     for rna_path in self.preset_defines:
74                         exec(rna_path)
75                         file_preset.write("%s\n" % rna_path)
76                     file_preset.write("\n")
77
78                 for rna_path in self.preset_values:
79                     value = eval(rna_path)
80                     # convert thin wrapped sequences to simple lists to repr()
81                     try:
82                         value = value[:]
83                     except:
84                         pass
85
86                     file_preset.write("%s = %r\n" % (rna_path, value))
87
88                 file_preset.close()
89
90             preset_menu_class.bl_label = bpy.path.display_name(filename)
91
92         else:
93             preset_active = preset_menu_class.bl_label
94
95             # fairly sloppy but convenient.
96             filepath = bpy.utils.preset_find(preset_active, self.preset_subdir)
97
98             if not filepath:
99                 filepath = bpy.utils.preset_find(preset_active, self.preset_subdir, display_name=True)
100
101             if not filepath:
102                 return {'CANCELLED'}
103
104             if hasattr(self, "remove"):
105                 self.remove(context, filepath)
106             else:
107                 try:
108                     os.remove(filepath)
109                 except:
110                     import traceback
111                     traceback.print_exc()
112
113             # XXX, stupid!
114             preset_menu_class.bl_label = "Presets"
115
116         if hasattr(self, "post_cb"):
117             self.post_cb(context)
118
119         return {'FINISHED'}
120
121     def check(self, context):
122         self.name = self.as_filename(self.name)
123
124     def invoke(self, context, event):
125         if not self.remove_active:
126             wm = context.window_manager
127             return wm.invoke_props_dialog(self)
128         else:
129             return self.execute(context)
130
131
132 class ExecutePreset(bpy.types.Operator):
133     ''' Executes a preset '''
134     bl_idname = "script.execute_preset"
135     bl_label = "Execute a Python Preset"
136
137     filepath = bpy.props.StringProperty(name="Path", description="Path of the Python file to execute", maxlen=512, default="")
138     menu_idname = bpy.props.StringProperty(name="Menu ID Name", description="ID name of the menu this was called from", default="")
139
140     def execute(self, context):
141         from os.path import basename
142         filepath = self.filepath
143
144         # change the menu title to the most recently chosen option
145         preset_class = getattr(bpy.types, self.menu_idname)
146         preset_class.bl_label = bpy.path.display_name(basename(filepath))
147
148         # execute the preset using script.python_file_run
149         bpy.ops.script.python_file_run(filepath=filepath)
150         return {'FINISHED'}
151
152
153 class AddPresetRender(AddPresetBase, bpy.types.Operator):
154     '''Add a Render Preset'''
155     bl_idname = "render.preset_add"
156     bl_label = "Add Render Preset"
157     preset_menu = "RENDER_MT_presets"
158
159     preset_defines = [
160         "scene = bpy.context.scene"
161     ]
162
163     preset_values = [
164         "scene.render.field_order",
165         "scene.render.fps",
166         "scene.render.fps_base",
167         "scene.render.pixel_aspect_x",
168         "scene.render.pixel_aspect_y",
169         "scene.render.resolution_percentage",
170         "scene.render.resolution_x",
171         "scene.render.resolution_y",
172         "scene.render.use_fields",
173         "scene.render.use_fields_still",
174     ]
175
176     preset_subdir = "render"
177
178
179 class AddPresetSSS(AddPresetBase, bpy.types.Operator):
180     '''Add a Subsurface Scattering Preset'''
181     bl_idname = "material.sss_preset_add"
182     bl_label = "Add SSS Preset"
183     preset_menu = "MATERIAL_MT_sss_presets"
184
185     preset_defines = [
186         "material = (bpy.context.material.active_node_material if bpy.context.material.active_node_material else bpy.context.material)"
187     ]
188
189     preset_values = [
190         "material.subsurface_scattering.back",
191         "material.subsurface_scattering.color",
192         "material.subsurface_scattering.color_factor",
193         "material.subsurface_scattering.error_threshold",
194         "material.subsurface_scattering.front",
195         "material.subsurface_scattering.ior",
196         "material.subsurface_scattering.radius",
197         "material.subsurface_scattering.scale",
198         "material.subsurface_scattering.texture_factor",
199     ]
200
201     preset_subdir = "sss"
202
203
204 class AddPresetCloth(AddPresetBase, bpy.types.Operator):
205     '''Add a Cloth Preset'''
206     bl_idname = "cloth.preset_add"
207     bl_label = "Add Cloth Preset"
208     preset_menu = "CLOTH_MT_presets"
209
210     preset_defines = [
211         "cloth = bpy.context.cloth"
212     ]
213
214     preset_values = [
215         "cloth.settings.air_damping",
216         "cloth.settings.bending_stiffness",
217         "cloth.settings.mass",
218         "cloth.settings.quality",
219         "cloth.settings.spring_damping",
220         "cloth.settings.structural_stiffness",
221     ]
222
223     preset_subdir = "cloth"
224
225
226 class AddPresetSunSky(AddPresetBase, bpy.types.Operator):
227     '''Add a Sky & Atmosphere Preset'''
228     bl_idname = "lamp.sunsky_preset_add"
229     bl_label = "Add Sunsky Preset"
230     preset_menu = "LAMP_MT_sunsky_presets"
231
232     preset_defines = [
233         "sky = bpy.context.object.data.sky"
234     ]
235
236     preset_values = [
237         "sky.atmosphere_extinction",
238         "sky.atmosphere_inscattering",
239         "sky.atmosphere_turbidity",
240         "sky.backscattered_light",
241         "sky.horizon_brightness",
242         "sky.spread",
243         "sky.sun_brightness",
244         "sky.sun_intensity",
245         "sky.sun_size",
246         "sky.use_sky_blend",
247         "sky.use_sky_blend_type",
248         "sky.use_sky_color_space",
249         "sky.use_sky_exposure",
250     ]
251
252     preset_subdir = "sunsky"
253
254
255 class AddPresetInteraction(AddPresetBase, bpy.types.Operator):
256     '''Add an Application Interaction Preset'''
257     bl_idname = "wm.interaction_preset_add"
258     bl_label = "Add Interaction Preset"
259     preset_menu = "USERPREF_MT_interaction_presets"
260
261     preset_defines = [
262         "user_preferences = bpy.context.user_preferences"
263     ]
264
265     preset_values = [
266         "user_preferences.edit.use_drag_immediately",
267         "user_preferences.edit.use_insertkey_xyz_to_rgb",
268         "user_preferences.inputs.invert_mouse_wheel_zoom",
269         "user_preferences.inputs.select_mouse",
270         "user_preferences.inputs.use_emulate_numpad",
271         "user_preferences.inputs.use_mouse_continuous",
272         "user_preferences.inputs.use_mouse_emulate_3_button",
273         "user_preferences.inputs.view_rotate_method",
274         "user_preferences.inputs.view_zoom_axis",
275         "user_preferences.inputs.view_zoom_method",
276     ]
277
278     preset_subdir = "interaction"
279
280
281 class AddPresetKeyconfig(AddPresetBase, bpy.types.Operator):
282     '''Add a Keyconfig Preset'''
283     bl_idname = "wm.keyconfig_preset_add"
284     bl_label = "Add Keyconfig Preset"
285     preset_menu = "USERPREF_MT_keyconfigs"
286     preset_subdir = "keyconfig"
287
288     def add(self, context, filepath):
289         bpy.ops.wm.keyconfig_export(filepath=filepath)
290         bpy.utils.keyconfig_set(filepath)
291
292     def pre_cb(self, context):
293         keyconfigs = bpy.context.window_manager.keyconfigs
294         if self.remove_active:
295             preset_menu_class = getattr(bpy.types, self.preset_menu)
296             preset_menu_class.bl_label = keyconfigs.active.name
297
298     def post_cb(self, context):
299         keyconfigs = bpy.context.window_manager.keyconfigs
300         if self.remove_active:
301             keyconfigs.remove(keyconfigs.active)
302
303
304 def register():
305     pass
306
307
308 def unregister():
309     pass
310
311 if __name__ == "__main__":
312     register()