4221fd8267db2ed1dbcc23b65f1876144c873e6b
[blender.git] / release / scripts / startup / bl_ui / space_topbar.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, Panel
22
23
24 class TOPBAR_HT_upper_bar(Header):
25     bl_space_type = 'TOPBAR'
26
27     def draw(self, context):
28         region = context.region
29
30         if region.alignment == 'RIGHT':
31             self.draw_right(context)
32         else:
33             self.draw_left(context)
34
35     def draw_left(self, context):
36         layout = self.layout
37
38         window = context.window
39         screen = context.screen
40
41         TOPBAR_MT_editor_menus.draw_collapsible(context, layout)
42
43         layout.separator()
44
45         if not screen.show_fullscreen:
46             layout.template_ID_tabs(
47                 window, "workspace",
48                 new="workspace.add",
49                 menu="TOPBAR_MT_workspace_menu",
50             )
51         else:
52             layout.operator(
53                 "screen.back_to_previous",
54                 icon='SCREEN_BACK',
55                 text="Back to Previous",
56             )
57
58     def draw_right(self, context):
59         layout = self.layout
60
61         window = context.window
62         screen = context.screen
63         scene = window.scene
64
65         # If statusbar is hidden, still show messages at the top
66         if not screen.show_statusbar:
67             layout.template_reports_banner()
68             layout.template_running_jobs()
69
70         # Active workspace view-layer is retrieved through window, not through workspace.
71         layout.template_ID(window, "scene", new="scene.new", unlink="scene.delete")
72
73         row = layout.row(align=True)
74         row.template_search(
75             window, "view_layer",
76             scene, "view_layers",
77             new="scene.view_layer_add",
78             unlink="scene.view_layer_remove")
79
80
81 class TOPBAR_PT_gpencil_layers(Panel):
82     bl_space_type = 'VIEW_3D'
83     bl_region_type = 'HEADER'
84     bl_label = "Layers"
85     bl_ui_units_x = 14
86
87     @classmethod
88     def poll(cls, context):
89         if context.gpencil_data is None:
90             return False
91
92         ob = context.object
93         if ob is not None and ob.type == 'GPENCIL':
94             return True
95
96         return False
97
98     def draw(self, context):
99         layout = self.layout
100         gpd = context.gpencil_data
101
102         # Grease Pencil data...
103         if (gpd is None) or (not gpd.layers):
104             layout.operator("gpencil.layer_add", text="New Layer")
105         else:
106             self.draw_layers(context, layout, gpd)
107
108     def draw_layers(self, context, layout, gpd):
109         row = layout.row()
110
111         col = row.column()
112         layer_rows = 10
113         col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index",
114                           rows=layer_rows, sort_reverse=True, sort_lock=True)
115
116         gpl = context.active_gpencil_layer
117         if gpl:
118             srow = col.row(align=True)
119             srow.prop(gpl, "blend_mode", text="Blend")
120
121             srow = col.row(align=True)
122             srow.prop(gpl, "opacity", text="Opacity", slider=True)
123             srow.prop(gpl, "clamp_layer", text="",
124                       icon='MOD_MASK' if gpl.clamp_layer else 'LAYER_ACTIVE')
125
126             srow = col.row(align=True)
127             srow.prop(gpl, "use_solo_mode", text="Show Only On Keyframed")
128
129         col = row.column()
130
131         sub = col.column(align=True)
132         sub.operator("gpencil.layer_add", icon='ADD', text="")
133         sub.operator("gpencil.layer_remove", icon='REMOVE', text="")
134
135         gpl = context.active_gpencil_layer
136         if gpl:
137             sub.menu("GPENCIL_MT_layer_context_menu", icon='DOWNARROW_HLT', text="")
138
139             if len(gpd.layers) > 1:
140                 col.separator()
141
142                 sub = col.column(align=True)
143                 sub.operator("gpencil.layer_move", icon='TRIA_UP', text="").type = 'UP'
144                 sub.operator("gpencil.layer_move", icon='TRIA_DOWN', text="").type = 'DOWN'
145
146                 col.separator()
147
148                 sub = col.column(align=True)
149                 sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
150                 sub.operator("gpencil.layer_isolate", icon='HIDE_OFF', text="").affect_visibility = True
151
152
153 class TOPBAR_MT_editor_menus(Menu):
154     bl_idname = "TOPBAR_MT_editor_menus"
155     bl_label = ""
156
157     def draw(self, _context):
158         layout = self.layout
159
160         layout.menu("TOPBAR_MT_app", text="", icon="BLENDER")
161
162         layout.menu("TOPBAR_MT_file")
163         layout.menu("TOPBAR_MT_edit")
164
165         layout.menu("TOPBAR_MT_render")
166
167         layout.menu("TOPBAR_MT_window")
168         layout.menu("TOPBAR_MT_help")
169
170
171 class TOPBAR_MT_app(Menu):
172     bl_label = "Blender"
173
174     def draw(self, context):
175         layout = self.layout
176         prefs = context.preferences
177
178         layout.operator("wm.splash")
179
180         layout.separator()
181
182         layout.menu("TOPBAR_MT_app_support")
183
184         layout.separator()
185
186         layout.menu("TOPBAR_MT_app_about")
187
188         layout.separator()
189
190         layout.operator("preferences.app_template_install", text="Install Application Template...")
191
192
193 class TOPBAR_MT_file(Menu):
194     bl_label = "File"
195
196     def draw(self, context):
197         layout = self.layout
198
199         layout.operator_context = 'INVOKE_AREA'
200         layout.menu("TOPBAR_MT_file_new", text="New", icon='FILE_NEW')
201         layout.operator("wm.open_mainfile", text="Open...", icon='FILE_FOLDER')
202         layout.menu("TOPBAR_MT_file_open_recent")
203         layout.operator("wm.revert_mainfile")
204         layout.menu("TOPBAR_MT_file_recover")
205
206         layout.separator()
207
208         layout.operator_context = 'EXEC_AREA' if context.blend_data.is_saved else 'INVOKE_AREA'
209         layout.operator("wm.save_mainfile", text="Save", icon='FILE_TICK')
210
211         layout.operator_context = 'INVOKE_AREA'
212         layout.operator("wm.save_as_mainfile", text="Save As...")
213         layout.operator_context = 'INVOKE_AREA'
214         layout.operator("wm.save_as_mainfile", text="Save Copy...").copy = True
215
216         layout.separator()
217
218         layout.operator_context = 'INVOKE_AREA'
219         layout.operator("wm.link", text="Link...", icon='LINK_BLEND')
220         layout.operator("wm.append", text="Append...", icon='APPEND_BLEND')
221         layout.menu("TOPBAR_MT_file_previews")
222
223         layout.separator()
224
225         layout.menu("TOPBAR_MT_file_import", icon='IMPORT')
226         layout.menu("TOPBAR_MT_file_export", icon='EXPORT')
227
228         layout.separator()
229
230         layout.menu("TOPBAR_MT_file_external_data")
231
232         layout.separator()
233
234         layout.menu("TOPBAR_MT_file_defaults")
235
236         layout.separator()
237
238         layout.operator_context = 'EXEC_AREA'
239         if bpy.data.is_dirty:
240             layout.operator_context = 'INVOKE_SCREEN'  # quit dialog
241         layout.operator("wm.quit_blender", text="Quit", icon='QUIT')
242
243
244 class TOPBAR_MT_file_new(Menu):
245     bl_label = "New File"
246
247     @staticmethod
248     def app_template_paths():
249         import os
250
251         template_paths = bpy.utils.app_template_paths()
252
253         # expand template paths
254         app_templates = []
255         for path in template_paths:
256             for d in os.listdir(path):
257                 if d.startswith(("__", ".")):
258                     continue
259                 template = os.path.join(path, d)
260                 if os.path.isdir(template):
261                     # template_paths_expand.append(template)
262                     app_templates.append(d)
263
264         return sorted(app_templates)
265
266     @staticmethod
267     def draw_ex(layout, _context, *, use_splash=False, use_more=False):
268         layout.operator_context = 'INVOKE_DEFAULT'
269
270         # Limit number of templates in splash screen, spill over into more menu.
271         paths = TOPBAR_MT_file_new.app_template_paths()
272         splash_limit = 5
273
274         if use_splash:
275             icon = 'FILE_NEW'
276             show_more = len(paths) > (splash_limit - 1)
277             if show_more:
278                 paths = paths[:splash_limit - 2]
279         elif use_more:
280             icon = 'FILE_NEW'
281             paths = paths[splash_limit - 2:]
282             show_more = False
283         else:
284             icon = 'NONE'
285             show_more = False
286
287         # Draw application templates.
288         if not use_more:
289             props = layout.operator("wm.read_homefile", text="General", icon=icon)
290             props.app_template = ""
291
292         for d in paths:
293             props = layout.operator(
294                 "wm.read_homefile",
295                 text=bpy.path.display_name(d),
296                 icon=icon,
297             )
298             props.app_template = d
299
300         layout.operator_context = 'EXEC_DEFAULT'
301
302         if show_more:
303             layout.menu("TOPBAR_MT_templates_more", text="...")
304
305     def draw(self, context):
306         TOPBAR_MT_file_new.draw_ex(self.layout, context)
307
308
309 class TOPBAR_MT_file_recover(Menu):
310     bl_label = "Recover"
311
312     def draw(self, context):
313         layout = self.layout
314
315         layout.operator("wm.recover_last_session", text="Last Session")
316         layout.operator("wm.recover_auto_save", text="Auto Save...")
317
318
319 class TOPBAR_MT_file_defaults(Menu):
320     bl_label = "Defaults"
321
322     def draw(self, context):
323         layout = self.layout
324         prefs = context.preferences
325
326         layout.operator_context = 'INVOKE_AREA'
327
328         if any(bpy.utils.app_template_paths()):
329             app_template = prefs.app_template
330         else:
331             app_template = None
332
333         if app_template:
334             layout.label(text=bpy.path.display_name(app_template, has_ext=False))
335
336         layout.operator("wm.save_homefile")
337         props = layout.operator("wm.read_factory_settings")
338         if app_template:
339             props.app_template = app_template
340
341         if prefs.use_preferences_save:
342             props = layout.operator(
343                 "wm.read_factory_settings",
344                 text="Load Factory Settings (Temporary)"
345             )
346             if app_template:
347                 props.app_template = app_template
348             props.use_temporary_preferences = True
349
350
351 class TOPBAR_MT_app_about(Menu):
352     bl_label = "About"
353
354     def draw(self, context):
355         layout = self.layout
356
357         layout.operator(
358             "wm.url_open", text="Release Notes", icon='URL',
359         ).url = "https://www.blender.org/download/releases/%d-%d/" % bpy.app.version[:2]
360
361         layout.separator()
362
363         layout.operator(
364             "wm.url_open", text="Blender Website", icon='URL',
365         ).url = "https://www.blender.org/"
366         layout.operator(
367             "wm.url_open", text="Credits", icon='URL',
368         ).url = "https://www.blender.org/about/credits/"
369
370         layout.separator()
371
372         layout.operator(
373             "wm.url_open", text="License", icon='URL',
374         ).url = "https://www.blender.org/about/license/"
375
376
377 class TOPBAR_MT_app_support(Menu):
378     bl_label = "Support Blender"
379
380     def draw(self, context):
381         layout = self.layout
382
383         layout.operator(
384             "wm.url_open", text="Development Fund", icon='URL',
385         ).url = "https://fund.blender.org"
386
387         layout.separator()
388
389         layout.operator(
390             "wm.url_open", text="Blender Store", icon='URL',
391         ).url = "https://store.blender.org"
392
393
394 class TOPBAR_MT_templates_more(Menu):
395     bl_label = "Templates"
396
397     def draw(self, context):
398         bpy.types.TOPBAR_MT_file_new.draw_ex(self.layout, context, use_more=True)
399
400
401 class TOPBAR_MT_file_import(Menu):
402     bl_idname = "TOPBAR_MT_file_import"
403     bl_label = "Import"
404
405     def draw(self, _context):
406         if bpy.app.build_options.collada:
407             self.layout.operator("wm.collada_import", text="Collada (Default) (.dae)")
408         if bpy.app.build_options.alembic:
409             self.layout.operator("wm.alembic_import", text="Alembic (.abc)")
410
411
412 class TOPBAR_MT_file_export(Menu):
413     bl_idname = "TOPBAR_MT_file_export"
414     bl_label = "Export"
415
416     def draw(self, _context):
417         if bpy.app.build_options.collada:
418             self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)")
419         if bpy.app.build_options.alembic:
420             self.layout.operator("wm.alembic_export", text="Alembic (.abc)")
421
422
423 class TOPBAR_MT_file_external_data(Menu):
424     bl_label = "External Data"
425
426     def draw(self, _context):
427         layout = self.layout
428
429         icon = 'CHECKBOX_HLT' if bpy.data.use_autopack else 'CHECKBOX_DEHLT'
430         layout.operator("file.autopack_toggle", icon=icon)
431
432         layout.separator()
433
434         pack_all = layout.row()
435         pack_all.operator("file.pack_all")
436         pack_all.active = not bpy.data.use_autopack
437
438         unpack_all = layout.row()
439         unpack_all.operator("file.unpack_all")
440         unpack_all.active = not bpy.data.use_autopack
441
442         layout.separator()
443
444         layout.operator("file.make_paths_relative")
445         layout.operator("file.make_paths_absolute")
446         layout.operator("file.report_missing_files")
447         layout.operator("file.find_missing_files")
448
449
450 class TOPBAR_MT_file_previews(Menu):
451     bl_label = "Data Previews"
452
453     def draw(self, _context):
454         layout = self.layout
455
456         layout.operator("wm.previews_ensure")
457         layout.operator("wm.previews_batch_generate")
458
459         layout.separator()
460
461         layout.operator("wm.previews_clear")
462         layout.operator("wm.previews_batch_clear")
463
464
465 class TOPBAR_MT_render(Menu):
466     bl_label = "Render"
467
468     def draw(self, context):
469         layout = self.layout
470
471         rd = context.scene.render
472
473         layout.operator("render.render", text="Render Image", icon='RENDER_STILL').use_viewport = True
474         props = layout.operator("render.render", text="Render Animation", icon='RENDER_ANIMATION')
475         props.animation = True
476         props.use_viewport = True
477
478         layout.separator()
479
480         layout.operator("sound.mixdown", text="Render Audio...")
481
482         layout.separator()
483
484         layout.operator("render.view_show", text="View Render")
485         layout.operator("render.play_rendered_anim", text="View Animation")
486         layout.prop_menu_enum(rd, "display_mode", text="Display Mode")
487
488         layout.separator()
489
490         layout.prop(rd, "use_lock_interface", text="Lock Interface")
491
492
493 class TOPBAR_MT_edit(Menu):
494     bl_label = "Edit"
495
496     def draw(self, context):
497         layout = self.layout
498
499         layout.operator("ed.undo")
500         layout.operator("ed.redo")
501
502         layout.separator()
503
504         layout.operator("ed.undo_history", text="Undo History...")
505
506         layout.separator()
507
508         layout.operator("screen.repeat_last")
509         layout.operator("screen.repeat_history", text="Repeat History...")
510
511         layout.separator()
512
513         layout.operator("screen.redo_last", text="Adjust Last Operation...")
514
515         layout.separator()
516
517         layout.operator("wm.search_menu", text="Operator Search...", icon='VIEWZOOM')
518
519         layout.separator()
520
521         # Mainly to expose shortcut since this depends on the context.
522         props = layout.operator("wm.call_panel", text="Rename Active Item...")
523         props.name = "TOPBAR_PT_name"
524         props.keep_open = False
525
526         layout.separator()
527
528         # Should move elsewhere (impacts outliner & 3D view).
529         tool_settings = context.tool_settings
530         layout.prop(tool_settings, "lock_object_mode")
531
532         layout.separator()
533
534         layout.operator("screen.userpref_show", text="Preferences...", icon='PREFERENCES')
535
536
537 class TOPBAR_MT_window(Menu):
538     bl_label = "Window"
539
540     def draw(self, context):
541         import sys
542
543         layout = self.layout
544
545         layout.operator("wm.window_new")
546         layout.operator("wm.window_new_main")
547
548         layout.separator()
549
550         layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER')
551
552         layout.separator()
553
554         layout.operator("screen.workspace_cycle", text="Next Workspace").direction = 'NEXT'
555         layout.operator("screen.workspace_cycle", text="Previous Workspace").direction = 'PREV'
556
557         layout.separator()
558
559         layout.prop(context.screen, "show_statusbar")
560
561         layout.separator()
562
563         layout.operator("screen.screenshot")
564
565         if sys.platform[:3] == "win":
566             layout.separator()
567             layout.operator("wm.console_toggle", icon='CONSOLE')
568
569         if context.scene.render.use_multiview:
570             layout.separator()
571             layout.operator("wm.set_stereo_3d")
572
573
574 class TOPBAR_MT_help(Menu):
575     bl_label = "Help"
576
577     def draw(self, context):
578         # If 'url_prefill_from_blender' becomes slow it could be made into a separate operator
579         # to avoid constructing the bug report just to show this menu.
580         from bl_ui_utils.bug_report_url import url_prefill_from_blender
581
582         layout = self.layout
583
584         show_developer = context.preferences.view.show_developer_ui
585
586         layout.operator(
587             "wm.url_open", text="Manual", icon='HELP',
588         ).url = "https://docs.blender.org/manual/en/dev/"
589         layout.operator(
590             "wm.url_open", text="Tutorials", icon='URL',
591         ).url = "https://www.blender.org/tutorials"
592         layout.operator(
593             "wm.url_open", text="Support", icon='URL',
594         ).url = "https://www.blender.org/support"
595
596         layout.separator()
597
598         layout.operator(
599             "wm.url_open", text="User Communities", icon='URL',
600         ).url = "https://www.blender.org/community/"
601         layout.operator(
602             "wm.url_open", text="Developer Community", icon='URL',
603         ).url = "https://devtalk.blender.org"
604
605         layout.separator()
606
607         layout.operator(
608             "wm.url_open", text="Python API Reference", icon='URL',
609         ).url = bpy.types.WM_OT_doc_view._prefix
610
611         if show_developer:
612             layout.operator(
613                 "wm.url_open", text="Developer Documentation", icon='URL',
614             ).url = "https://wiki.blender.org/wiki/Main_Page"
615
616             layout.operator("wm.operator_cheat_sheet", icon='TEXT')
617
618         layout.separator()
619
620         layout.operator(
621             "wm.url_open", text="Report a Bug", icon='URL',
622         ).url = url_prefill_from_blender()
623
624         layout.separator()
625
626         layout.operator("wm.sysinfo")
627
628
629 class TOPBAR_MT_file_context_menu(Menu):
630     bl_label = "File Context Menu"
631
632     def draw(self, _context):
633         layout = self.layout
634
635         layout.operator_context = 'INVOKE_AREA'
636         layout.menu("TOPBAR_MT_file_new", text="New", icon='FILE_NEW')
637         layout.operator("wm.open_mainfile", text="Open...", icon='FILE_FOLDER')
638
639         layout.separator()
640
641         layout.operator("wm.link", text="Link...", icon='LINK_BLEND')
642         layout.operator("wm.append", text="Append...", icon='APPEND_BLEND')
643
644         layout.separator()
645
646         layout.menu("TOPBAR_MT_file_import", icon='IMPORT')
647         layout.menu("TOPBAR_MT_file_export", icon='EXPORT')
648
649         layout.separator()
650
651         layout.operator("screen.userpref_show", text="Preferences...", icon='PREFERENCES')
652
653
654 class TOPBAR_MT_workspace_menu(Menu):
655     bl_label = "Workspace"
656
657     def draw(self, _context):
658         layout = self.layout
659
660         layout.operator("workspace.duplicate", text="Duplicate", icon='DUPLICATE')
661         if len(bpy.data.workspaces) > 1:
662             layout.operator("workspace.delete", text="Delete", icon='REMOVE')
663
664         layout.separator()
665
666         layout.operator("workspace.reorder_to_front", text="Reorder to Front", icon='TRIA_LEFT_BAR')
667         layout.operator("workspace.reorder_to_back", text="Reorder to Back", icon='TRIA_RIGHT_BAR')
668
669         layout.separator()
670
671         # For key binding discoverability.
672         props = layout.operator("screen.workspace_cycle", text="Previous Workspace")
673         props.direction = 'PREV'
674         props = layout.operator("screen.workspace_cycle", text="Next Workspace")
675         props.direction = 'NEXT'
676
677
678 # Grease Pencil Object - Primitive curve
679 class TOPBAR_PT_gpencil_primitive(Panel):
680     bl_space_type = 'VIEW_3D'
681     bl_region_type = 'HEADER'
682     bl_label = "Primitives"
683
684     def draw(self, context):
685         settings = context.tool_settings.gpencil_sculpt
686
687         layout = self.layout
688         # Curve
689         layout.template_curve_mapping(settings, "thickness_primitive_curve", brush=True)
690
691
692 # Grease Pencil Fill
693 class TOPBAR_PT_gpencil_fill(Panel):
694     bl_space_type = 'VIEW_3D'
695     bl_region_type = 'HEADER'
696     bl_label = "Advanced"
697
698     def draw(self, context):
699         paint = context.tool_settings.gpencil_paint
700         brush = paint.brush
701         gp_settings = brush.gpencil_settings
702
703         layout = self.layout
704         # Fill
705         row = layout.row(align=True)
706         row.prop(gp_settings, "fill_factor", text="Resolution")
707         if gp_settings.fill_draw_mode != 'STROKE':
708             row = layout.row(align=True)
709             row.prop(gp_settings, "show_fill", text="Ignore Transparent Strokes")
710             row = layout.row(align=True)
711             row.prop(gp_settings, "fill_threshold", text="Threshold")
712
713
714 # Only a popover
715 class TOPBAR_PT_name(Panel):
716     bl_space_type = 'TOPBAR'  # dummy
717     bl_region_type = 'HEADER'
718     bl_label = "Rename Active Item"
719     bl_ui_units_x = 14
720
721     def draw(self, context):
722         layout = self.layout
723
724         # Edit first editable button in popup
725         def row_with_icon(layout, icon):
726             row = layout.row()
727             row.activate_init = True
728             row.label(icon=icon)
729             return row
730
731         mode = context.mode
732         scene = context.scene
733         space = context.space_data
734         space_type = None if (space is None) else space.type
735         found = False
736         if space_type == 'SEQUENCE_EDITOR':
737             layout.label(text="Sequence Strip Name")
738             item = getattr(scene.sequence_editor, "active_strip")
739             if item:
740                 row = row_with_icon(layout, 'SEQUENCE')
741                 row.prop(item, "name", text="")
742                 found = True
743         elif space_type == 'NODE_EDITOR':
744             layout.label(text="Node Label")
745             item = context.active_node
746             if item:
747                 row = row_with_icon(layout, 'NODE')
748                 row.prop(item, "label", text="")
749                 found = True
750         else:
751             if mode == 'POSE' or (mode == 'WEIGHT_PAINT' and context.pose_object):
752                 layout.label(text="Bone Name")
753                 item = context.active_pose_bone
754                 if item:
755                     row = row_with_icon(layout, 'BONE_DATA')
756                     row.prop(item, "name", text="")
757                     found = True
758             elif mode == 'EDIT_ARMATURE':
759                 layout.label(text="Bone Name")
760                 item = context.active_bone
761                 if item:
762                     row = row_with_icon(layout, 'BONE_DATA')
763                     row.prop(item, "name", text="")
764                     found = True
765             else:
766                 layout.label(text="Object Name")
767                 item = context.object
768                 if item:
769                     row = row_with_icon(layout, 'OBJECT_DATA')
770                     row.prop(item, "name", text="")
771                     found = True
772
773         if not found:
774             row = row_with_icon(layout, 'ERROR')
775             row.label(text="No active item")
776
777
778 classes = (
779     TOPBAR_HT_upper_bar,
780     TOPBAR_MT_file_context_menu,
781     TOPBAR_MT_workspace_menu,
782     TOPBAR_MT_editor_menus,
783     TOPBAR_MT_app,
784     TOPBAR_MT_app_about,
785     TOPBAR_MT_app_support,
786     TOPBAR_MT_file,
787     TOPBAR_MT_file_new,
788     TOPBAR_MT_file_recover,
789     TOPBAR_MT_file_defaults,
790     TOPBAR_MT_templates_more,
791     TOPBAR_MT_file_import,
792     TOPBAR_MT_file_export,
793     TOPBAR_MT_file_external_data,
794     TOPBAR_MT_file_previews,
795     TOPBAR_MT_edit,
796     TOPBAR_MT_render,
797     TOPBAR_MT_window,
798     TOPBAR_MT_help,
799     TOPBAR_PT_gpencil_layers,
800     TOPBAR_PT_gpencil_primitive,
801     TOPBAR_PT_gpencil_fill,
802     TOPBAR_PT_name,
803 )
804
805 if __name__ == "__main__":  # only for live edit.
806     from bpy.utils import register_class
807     for cls in classes:
808         register_class(cls)