Merge branch 'blender-v2.91-release'
[blender.git] / release / scripts / startup / bl_ui / __init__.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
21 # note, properties_animviz is a helper module only.
22
23 # support reloading sub-modules
24 if "bpy" in locals():
25     from importlib import reload
26     _modules_loaded[:] = [reload(val) for val in _modules_loaded]
27     del reload
28
29 _modules = [
30     "properties_animviz",
31     "properties_constraint",
32     "properties_data_armature",
33     "properties_data_bone",
34     "properties_data_camera",
35     "properties_data_curve",
36     "properties_data_empty",
37     "properties_data_gpencil",
38     "properties_data_hair",
39     "properties_data_light",
40     "properties_data_lattice",
41     "properties_data_mesh",
42     "properties_data_metaball",
43     "properties_data_modifier",
44     "properties_data_pointcloud",
45     "properties_data_shaderfx",
46     "properties_data_lightprobe",
47     "properties_data_speaker",
48     "properties_data_volume",
49     "properties_mask_common",
50     "properties_material",
51     "properties_material_gpencil",
52     "properties_object",
53     "properties_paint_common",
54     "properties_grease_pencil_common",
55     "properties_particle",
56     "properties_physics_cloth",
57     "properties_physics_common",
58     "properties_physics_dynamicpaint",
59     "properties_physics_field",
60     "properties_physics_rigidbody",
61     "properties_physics_rigidbody_constraint",
62     "properties_physics_fluid",
63     "properties_physics_softbody",
64     "properties_render",
65     "properties_output",
66     "properties_view_layer",
67     "properties_scene",
68     "properties_texture",
69     "properties_world",
70
71     # Generic Space Modules
72     #
73     # Depends on DNA_WORKSPACE_TOOL (C define).
74     "space_toolsystem_common",
75     "space_toolsystem_toolbar",
76
77     "space_clip",
78     "space_console",
79     "space_dopesheet",
80     "space_filebrowser",
81     "space_graph",
82     "space_image",
83     "space_info",
84     "space_nla",
85     "space_node",
86     "space_outliner",
87     "space_properties",
88     "space_sequencer",
89     "space_statusbar",
90     "space_text",
91     "space_time",
92     "space_topbar",
93     "space_userpref",
94     "space_view3d",
95     "space_view3d_toolbar",
96
97     # XXX, keep last so panels show after all other tool options.
98     "properties_workspace",
99 ]
100
101 import bpy
102
103 if bpy.app.build_options.freestyle:
104     _modules.append("properties_freestyle")
105
106 __import__(name=__name__, fromlist=_modules)
107 _namespace = globals()
108 _modules_loaded = [_namespace[name] for name in _modules]
109 del _namespace
110
111
112 def register():
113     from bpy.utils import register_class
114     for mod in _modules_loaded:
115         for cls in mod.classes:
116             register_class(cls)
117
118     # space_userprefs.py
119     from bpy.props import (
120         EnumProperty,
121         StringProperty,
122     )
123     from bpy.types import WindowManager
124
125     def addon_filter_items(_self, _context):
126         import addon_utils
127
128         items = [
129             ('All', "All", "All Add-ons"),
130             ('User', "User", "All Add-ons Installed by User"),
131         ]
132
133         items_unique = set()
134
135         for mod in addon_utils.modules(refresh=False):
136             info = addon_utils.module_bl_info(mod)
137             items_unique.add(info["category"])
138
139         items.extend([(cat, cat, "") for cat in sorted(items_unique)])
140         return items
141
142     WindowManager.addon_search = StringProperty(
143         name="Search",
144         description="Search within the selected filter",
145         options={'TEXTEDIT_UPDATE'},
146     )
147     WindowManager.addon_filter = EnumProperty(
148         items=addon_filter_items,
149         name="Category",
150         description="Filter add-ons by category",
151     )
152
153     WindowManager.addon_support = EnumProperty(
154         items=[
155             ('OFFICIAL', "Official", "Officially supported"),
156             ('COMMUNITY', "Community", "Maintained by community developers"),
157             ('TESTING', "Testing", "Newly contributed scripts (excluded from release builds)")
158         ],
159         name="Support",
160         description="Display support level",
161         default={'OFFICIAL', 'COMMUNITY'},
162         options={'ENUM_FLAG'},
163     )
164     # done...
165
166
167 def unregister():
168     from bpy.utils import unregister_class
169     for mod in reversed(_modules_loaded):
170         for cls in reversed(mod.classes):
171             if cls.is_registered:
172                 unregister_class(cls)
173
174 # Define a default UIList, when a list does not need any custom drawing...
175 # Keep in sync with its #defined name in UI_interface.h
176
177
178 class UI_UL_list(bpy.types.UIList):
179     # These are common filtering or ordering operations (same as the default C ones!).
180     @staticmethod
181     def filter_items_by_name(pattern, bitflag, items, propname="name", flags=None, reverse=False):
182         """
183         Set FILTER_ITEM for items which name matches filter_name one (case-insensitive).
184         pattern is the filtering pattern.
185         propname is the name of the string property to use for filtering.
186         flags must be a list of integers the same length as items, or None!
187         return a list of flags (based on given flags if not None),
188         or an empty list if no flags were given and no filtering has been done.
189         """
190         import fnmatch
191
192         if not pattern or not items:  # Empty pattern or list = no filtering!
193             return flags or []
194
195         if flags is None:
196             flags = [0] * len(items)
197
198         # Implicitly add heading/trailing wildcards.
199         pattern = "*" + pattern + "*"
200
201         for i, item in enumerate(items):
202             name = getattr(item, propname, None)
203             # This is similar to a logical xor
204             if bool(name and fnmatch.fnmatch(name, pattern)) is not bool(reverse):
205                 flags[i] |= bitflag
206         return flags
207
208     @staticmethod
209     def sort_items_helper(sort_data, key, reverse=False):
210         """
211         Common sorting utility. Returns a neworder list mapping org_idx -> new_idx.
212         sort_data must be an (unordered) list of tuples [(org_idx, ...), (org_idx, ...), ...].
213         key must be the same kind of callable you would use for sorted() builtin function.
214         reverse will reverse the sorting!
215         """
216         sort_data.sort(key=key, reverse=reverse)
217         neworder = [None] * len(sort_data)
218         for newidx, (orgidx, *_) in enumerate(sort_data):
219             neworder[orgidx] = newidx
220         return neworder
221
222     @classmethod
223     def sort_items_by_name(cls, items, propname="name"):
224         """
225         Re-order items using their names (case-insensitive).
226         propname is the name of the string property to use for sorting.
227         return a list mapping org_idx -> new_idx,
228                or an empty list if no sorting has been done.
229         """
230         _sort = [(idx, getattr(it, propname, "")) for idx, it in enumerate(items)]
231         return cls.sort_items_helper(_sort, lambda e: e[1].lower())
232
233
234 bpy.utils.register_class(UI_UL_list)