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 #####
20 "name": "UI Classes Overview",
21 "author": "lijenstina",
23 "blender": (2, 80, 0),
24 "location": "Text Editor > Properties",
25 "description": "Print the UI classes in a text-block",
27 "doc_url": "https://wiki.blender.org/index.php/Extensions:2.6/"
28 "Py/Scripts/Development/Classes_Overview",
29 "category": "Development",
33 from bpy
.types
import (
38 from bpy
.props
import (
45 class TEXT_PT_ui_cheat_sheet(Panel
):
46 bl_space_type
= "TEXT_EDITOR"
48 bl_label
= "UI Cheat Sheet"
50 bl_options
= {"DEFAULT_CLOSED"}
52 def draw(self
, context
):
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"
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
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
)
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
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}'
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
__():
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
)
138 self
.report({'WARNING'},
139 "Failure to write the UI list (Check the console for more info)")
141 traceback
.print_exc()
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"),
158 searchable
: BoolProperty(
159 name
="Format searchable",
160 description
="Generate the list as Python dictionary,\n"
161 "using the format Class: Path",
168 TEXT_OT_ui_cheat_sheet
,
169 TEXT_PT_ui_cheat_sheet
,
176 bpy
.utils
.register_class(cls
)
178 bpy
.types
.Scene
.dev_text_ui
= PointerProperty(type=text_ui_cheat_props
)
183 bpy
.utils
.unregister_class(cls
)
185 del bpy
.types
.Scene
.dev_text_ui
188 if __name__
== "__main__":