Fix T54477: Broken utf8 strings in old .blend files
[blender.git] / release / scripts / startup / bl_ui / space_info.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 import bpy
21 from bpy.types import Header, Menu
22
23
24 class INFO_HT_header(Header):
25     bl_space_type = 'INFO'
26
27     def draw(self, context):
28         layout = self.layout
29
30         window = context.window
31         scene = context.scene
32         rd = scene.render
33
34         row = layout.row(align=True)
35         row.template_header()
36
37         INFO_MT_editor_menus.draw_collapsible(context, layout)
38
39         if window.screen.show_fullscreen:
40             layout.operator("screen.back_to_previous", icon='SCREEN_BACK', text="Back to Previous")
41             layout.separator()
42         else:
43             layout.template_ID(context.window, "screen", new="screen.new", unlink="screen.delete")
44             layout.template_ID(context.screen, "scene", new="scene.new", unlink="scene.delete")
45
46         layout.separator()
47
48         if rd.has_multiple_engines:
49             layout.prop(rd, "engine", text="")
50
51         layout.separator()
52
53         layout.template_running_jobs()
54
55         layout.template_reports_banner()
56
57         row = layout.row(align=True)
58
59         if bpy.app.autoexec_fail is True and bpy.app.autoexec_fail_quiet is False:
60             row.label("Auto-run disabled", icon='ERROR')
61             if bpy.data.is_saved:
62                 props = row.operator("wm.revert_mainfile", icon='SCREEN_BACK', text="Reload Trusted")
63                 props.use_scripts = True
64
65             row.operator("script.autoexec_warn_clear", text="Ignore")
66
67             # include last so text doesn't push buttons out of the header
68             row.label(bpy.app.autoexec_fail_message)
69             return
70
71         row.operator("wm.splash", text="", icon='BLENDER', emboss=False)
72         row.label(text=scene.statistics(), translate=False)
73
74
75 class INFO_MT_editor_menus(Menu):
76     bl_idname = "INFO_MT_editor_menus"
77     bl_label = ""
78
79     def draw(self, context):
80         self.draw_menus(self.layout, context)
81
82     @staticmethod
83     def draw_menus(layout, context):
84         scene = context.scene
85         rd = scene.render
86
87         layout.menu("INFO_MT_file")
88
89         if rd.use_game_engine:
90             layout.menu("INFO_MT_game")
91         else:
92             layout.menu("INFO_MT_render")
93
94         layout.menu("INFO_MT_window")
95         layout.menu("INFO_MT_help")
96
97
98 class INFO_MT_file(Menu):
99     bl_label = "File"
100
101     def draw(self, context):
102         layout = self.layout
103
104         layout.operator_context = 'INVOKE_AREA'
105         layout.operator("wm.read_homefile", text="New", icon='NEW')
106         layout.operator("wm.open_mainfile", text="Open...", icon='FILE_FOLDER')
107         layout.menu("INFO_MT_file_open_recent", icon='OPEN_RECENT')
108         layout.operator("wm.revert_mainfile", icon='FILE_REFRESH')
109         layout.operator("wm.recover_last_session", icon='RECOVER_LAST')
110         layout.operator("wm.recover_auto_save", text="Recover Auto Save...", icon='RECOVER_AUTO')
111
112         layout.separator()
113
114         layout.operator_context = 'EXEC_AREA' if context.blend_data.is_saved else 'INVOKE_AREA'
115         layout.operator("wm.save_mainfile", text="Save", icon='FILE_TICK')
116
117         layout.operator_context = 'INVOKE_AREA'
118         layout.operator("wm.save_as_mainfile", text="Save As...", icon='SAVE_AS')
119         layout.operator_context = 'INVOKE_AREA'
120         layout.operator("wm.save_as_mainfile", text="Save Copy...", icon='SAVE_COPY').copy = True
121
122         layout.separator()
123
124         layout.operator("screen.userpref_show", text="User Preferences...", icon='PREFERENCES')
125
126         layout.operator_context = 'INVOKE_AREA'
127         layout.operator("wm.save_homefile", icon='SAVE_PREFS')
128         layout.operator("wm.read_factory_settings", icon='LOAD_FACTORY')
129
130         if any(bpy.utils.app_template_paths()):
131             app_template = context.user_preferences.app_template
132             if app_template:
133                 layout.operator(
134                     "wm.read_factory_settings",
135                     text="Load Factory Template Settings",
136                     icon='LOAD_FACTORY',
137                 ).app_template = app_template
138             del app_template
139
140         layout.menu("USERPREF_MT_app_templates", icon='FILE_BLEND')
141
142         layout.separator()
143
144         layout.operator_context = 'INVOKE_AREA'
145         layout.operator("wm.link", text="Link", icon='LINK_BLEND')
146         layout.operator("wm.append", text="Append", icon='APPEND_BLEND')
147         layout.menu("INFO_MT_file_previews")
148
149         layout.separator()
150
151         layout.menu("INFO_MT_file_import", icon='IMPORT')
152         layout.menu("INFO_MT_file_export", icon='EXPORT')
153
154         layout.separator()
155
156         layout.menu("INFO_MT_file_external_data", icon='EXTERNAL_DATA')
157         layout.operator("wm.blend_strings_utf8_validate", icon='FILE_BLEND')
158
159         layout.separator()
160
161         layout.operator_context = 'EXEC_AREA'
162         if bpy.data.is_dirty and context.user_preferences.view.use_quit_dialog:
163             layout.operator_context = 'INVOKE_SCREEN'  # quit dialog
164         layout.operator("wm.quit_blender", text="Quit", icon='QUIT')
165
166
167 class INFO_MT_file_import(Menu):
168     bl_idname = "INFO_MT_file_import"
169     bl_label = "Import"
170
171     def draw(self, context):
172         if bpy.app.build_options.collada:
173             self.layout.operator("wm.collada_import", text="Collada (Default) (.dae)")
174         if bpy.app.build_options.alembic:
175             self.layout.operator("wm.alembic_import", text="Alembic (.abc)")
176
177
178 class INFO_MT_file_export(Menu):
179     bl_idname = "INFO_MT_file_export"
180     bl_label = "Export"
181
182     def draw(self, context):
183         if bpy.app.build_options.collada:
184             self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)")
185         if bpy.app.build_options.alembic:
186             self.layout.operator("wm.alembic_export", text="Alembic (.abc)")
187
188
189 class INFO_MT_file_external_data(Menu):
190     bl_label = "External Data"
191
192     def draw(self, context):
193         layout = self.layout
194
195         icon = 'CHECKBOX_HLT' if bpy.data.use_autopack else 'CHECKBOX_DEHLT'
196         layout.operator("file.autopack_toggle", icon=icon)
197
198         layout.separator()
199
200         pack_all = layout.row()
201         pack_all.operator("file.pack_all")
202         pack_all.active = not bpy.data.use_autopack
203
204         unpack_all = layout.row()
205         unpack_all.operator("file.unpack_all")
206         unpack_all.active = not bpy.data.use_autopack
207
208         layout.separator()
209
210         layout.operator("file.make_paths_relative")
211         layout.operator("file.make_paths_absolute")
212         layout.operator("file.report_missing_files")
213         layout.operator("file.find_missing_files")
214
215
216 class INFO_MT_file_previews(Menu):
217     bl_label = "Data Previews"
218
219     def draw(self, context):
220         layout = self.layout
221
222         layout.operator("wm.previews_ensure")
223         layout.operator("wm.previews_batch_generate")
224
225         layout.separator()
226
227         layout.operator("wm.previews_clear")
228         layout.operator("wm.previews_batch_clear")
229
230
231 class INFO_MT_game(Menu):
232     bl_label = "Game"
233
234     def draw(self, context):
235         layout = self.layout
236
237         gs = context.scene.game_settings
238
239         layout.operator("view3d.game_start")
240
241         layout.separator()
242
243         layout.prop(gs, "show_debug_properties")
244         layout.prop(gs, "show_framerate_profile")
245         layout.prop(gs, "show_physics_visualization")
246         layout.prop(gs, "use_deprecation_warnings")
247         layout.prop(gs, "use_animation_record")
248         layout.separator()
249         layout.prop(gs, "use_auto_start")
250
251
252 class INFO_MT_render(Menu):
253     bl_label = "Render"
254
255     def draw(self, context):
256         layout = self.layout
257
258         layout.operator("render.render", text="Render Image", icon='RENDER_STILL').use_viewport = True
259         props = layout.operator("render.render", text="Render Animation", icon='RENDER_ANIMATION')
260         props.animation = True
261         props.use_viewport = True
262
263         layout.separator()
264
265         layout.operator("render.opengl", text="OpenGL Render Image")
266         layout.operator("render.opengl", text="OpenGL Render Animation").animation = True
267         layout.menu("INFO_MT_opengl_render")
268
269         layout.separator()
270
271         layout.operator("render.view_show")
272         layout.operator("render.play_rendered_anim", icon='PLAY')
273
274
275 class INFO_MT_opengl_render(Menu):
276     bl_label = "OpenGL Render Options"
277
278     def draw(self, context):
279         layout = self.layout
280
281         rd = context.scene.render
282         layout.prop(rd, "use_antialiasing")
283         layout.prop(rd, "use_full_sample")
284
285         layout.prop_menu_enum(rd, "antialiasing_samples")
286         layout.prop_menu_enum(rd, "alpha_mode")
287
288
289 class INFO_MT_window(Menu):
290     bl_label = "Window"
291
292     def draw(self, context):
293         import sys
294
295         layout = self.layout
296
297         layout.operator("wm.window_duplicate")
298         layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER')
299
300         layout.separator()
301
302         layout.operator("screen.screenshot")
303         layout.operator("screen.screencast")
304
305         if sys.platform[:3] == "win":
306             layout.separator()
307             layout.operator("wm.console_toggle", icon='CONSOLE')
308
309         if context.scene.render.use_multiview:
310             layout.separator()
311             layout.operator("wm.set_stereo_3d", icon='CAMERA_STEREO')
312
313
314 class INFO_MT_help(Menu):
315     bl_label = "Help"
316
317     def draw(self, context):
318         layout = self.layout
319
320         layout.operator(
321                 "wm.url_open", text="Manual", icon='HELP',
322                 ).url = "https://docs.blender.org/manual/en/dev/"
323         layout.operator(
324                 "wm.url_open", text="Release Log", icon='URL',
325                 ).url = "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d" % bpy.app.version[:2]
326         layout.separator()
327
328         layout.operator(
329                 "wm.url_open", text="Blender Website", icon='URL',
330                 ).url = "https://www.blender.org"
331         layout.operator(
332                 "wm.url_open", text="Blender Store", icon='URL',
333                 ).url = "https://store.blender.org"
334         layout.operator(
335                 "wm.url_open", text="Developer Community", icon='URL',
336                 ).url = "https://www.blender.org/get-involved/"
337         layout.operator(
338                 "wm.url_open", text="User Community", icon='URL',
339                 ).url = "https://www.blender.org/support/user-community"
340         layout.separator()
341         layout.operator(
342                 "wm.url_open", text="Report a Bug", icon='URL',
343                 ).url = "https://developer.blender.org/maniphest/task/edit/form/1"
344         layout.separator()
345
346         layout.operator(
347                 "wm.url_open", text="Python API Reference", icon='URL',
348                 ).url = bpy.types.WM_OT_doc_view._prefix
349
350         layout.operator("wm.operator_cheat_sheet", icon='TEXT')
351         layout.operator("wm.sysinfo", icon='TEXT')
352         layout.separator()
353
354         layout.operator("wm.splash", icon='BLENDER')
355
356
357 classes = (
358     INFO_HT_header,
359     INFO_MT_editor_menus,
360     INFO_MT_file,
361     INFO_MT_file_import,
362     INFO_MT_file_export,
363     INFO_MT_file_external_data,
364     INFO_MT_file_previews,
365     INFO_MT_game,
366     INFO_MT_render,
367     INFO_MT_opengl_render,
368     INFO_MT_window,
369     INFO_MT_help,
370 )
371
372 if __name__ == "__main__":  # only for live edit.
373     from bpy.utils import register_class
374     for cls in classes:
375         register_class(cls)