UI: Move Extensions repositories popover to header
[blender-addons-contrib.git] / development_ui_classes.py
blob24918c00c513e8b1951a0d8b60dd1e9ae9200cb6
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 #####
19 bl_info = {
20 "name": "UI Classes Overview",
21 "author": "lijenstina",
22 "version": (1, 0, 2),
23 "blender": (2, 80, 0),
24 "location": "Text Editor > Properties",
25 "description": "Print the UI classes in a text-block",
26 "warning": "",
27 "doc_url": "https://wiki.blender.org/index.php/Extensions:2.6/"
28 "Py/Scripts/Development/Classes_Overview",
29 "category": "Development",
32 import bpy
33 from bpy.types import (
34 Operator,
35 Panel,
36 PropertyGroup,
38 from bpy.props import (
39 BoolProperty,
40 EnumProperty,
41 PointerProperty,
45 class TEXT_PT_ui_cheat_sheet(Panel):
46 bl_space_type = "TEXT_EDITOR"
47 bl_region_type = "UI"
48 bl_label = "UI Cheat Sheet"
49 bl_category = 'Dev'
50 bl_options = {"DEFAULT_CLOSED"}
52 def draw(self, context):
53 layout = self.layout
54 scene = context.scene.dev_text_ui
56 col = layout.column(align=True)
57 col.prop(scene, "dev_ui_cheat_type", expand=True)
59 row = layout.row(align=True)
60 split = row.split(factor=0.8, align=True)
61 split.operator("text.ui_cheat_sheet")
62 split.prop(scene, "searchable", text="", icon='SHORTDISPLAY')
65 class TEXT_OT_ui_cheat_sheet(Operator):
66 bl_idname = "text.ui_cheat_sheet"
67 bl_label = "Generate UI list"
68 bl_description = ("List the UI Menus, Panels and Headers in a textblock\n"
69 "The newly generated list will be made active in the Text Editor\n"
70 "To access the previous ones, select them from the Header dropdown")
72 def ui_list_name(self, context):
73 new_name, def_name, ext = "", "UIList", ".txt"
74 suffix = 1
75 try:
76 # first slap a simple linear count + 1 for numeric suffix, if it fails
77 # harvest for the rightmost numbers and append the max value
78 list_txt = []
79 data_txt = bpy.data.texts
80 list_txt = [txt.name for txt in data_txt if txt.name.startswith("UIList")]
81 new_name = "{}_{}{}".format(def_name, len(list_txt) + 1, ext)
83 if new_name in list_txt:
84 from re import findall
85 test_num = [findall("\d+", words) for words in list_txt]
86 suffix += max([int(l[-1]) for l in test_num])
87 new_name = "{}_{}{}".format(def_name, suffix, ext)
88 return new_name
89 except:
90 return None
92 def execute(self, context):
93 from collections import defaultdict
95 scene = context.scene.dev_text_ui
96 ui_type = scene.dev_ui_cheat_type
97 op_string_ui = defaultdict(list)
98 searchable = scene.searchable
100 try:
101 file_name = self.ui_list_name(context) or "UIList.txt"
102 classes = ["Panel", "Menu", "Header"] if ui_type in "all" else [ui_type]
103 string_line = "---\n%s\nModule path: %s" if not searchable else "\n'%s': '%s',"
104 print_line = '\n\n\n[%s]\nitems: %d\n' if not searchable else '\n\n%s = {\n# items: %d\n'
105 close_line = '\n' if not searchable else '\n}'
106 start_note = (
107 "\n\n# Classes starting with 'NODE_PT_category_' and 'NODE_MT_category_'\n"
108 "# are generated in startup\\nodeitems_builtins.py" if ui_type not in "Header" else ""
111 for cls_name in classes:
112 cls = getattr(bpy.types, cls_name)
113 for op_module in cls.__subclasses__():
114 if op_module:
115 module_name = op_module.__module__
116 module_name = module_name.replace('.', '\\')
117 text = (string_line % (op_module.__name__, module_name))
118 op_string_ui[cls_name].append(text)
120 textblock = bpy.data.texts.new(file_name)
121 total = sum([len(op_string_ui[cls_name]) for cls_name in classes])
122 textblock.write('# %d Total Items' % (total))
123 textblock.write(start_note)
125 for cls_name in classes:
126 textblock.write(print_line % (cls_name, len(op_string_ui[cls_name])))
127 textblock.write(('\n' if not searchable else '').join(sorted(op_string_ui[cls_name])))
128 textblock.write(close_line)
130 # try to set the created text block to active
131 if context.area.type in {"TEXT_EDITOR"}:
132 bpy.context.space_data.text = bpy.data.texts[file_name]
134 self.report({'INFO'}, "See %s textblock" % file_name)
136 return {'FINISHED'}
137 except:
138 self.report({'WARNING'},
139 "Failure to write the UI list (Check the console for more info)")
140 import traceback
141 traceback.print_exc()
143 return {'CANCELLED'}
146 # Properties
147 class text_ui_cheat_props(PropertyGroup):
148 dev_ui_cheat_type: EnumProperty(
149 name="Choose a Type",
150 description="Choose what Classes to include in a Text-Block",
151 items=(('all', "All", "Print all the types"),
152 ('Panel', "Panels", "Print Panel UI types"),
153 ('Menu', "Menus", "Print Menu UI types"),
154 ('Header', "Headers", "Print Header UI types"),
156 default='all',
158 searchable: BoolProperty(
159 name="Format searchable",
160 description="Generate the list as Python dictionary,\n"
161 "using the format Class: Path",
162 default=False
166 # Register
167 classes = (
168 TEXT_OT_ui_cheat_sheet,
169 TEXT_PT_ui_cheat_sheet,
170 text_ui_cheat_props
174 def register():
175 for cls in classes:
176 bpy.utils.register_class(cls)
178 bpy.types.Scene.dev_text_ui = PointerProperty(type=text_ui_cheat_props)
181 def unregister():
182 for cls in classes:
183 bpy.utils.unregister_class(cls)
185 del bpy.types.Scene.dev_text_ui
188 if __name__ == "__main__":
189 register()