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