Fix T99542: 3D print toolbox thickness check causes assertion
[blender-addons.git] / space_view3d_pie_menus / __init__.py
blobcb539e31b3f8fde5c1c85d3e4de175ead0afc9bd
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # Contributed to by meta-androcto, pitiwazou, chromoly, italic
5 import bpy
6 from bpy.props import (
7 BoolProperty,
8 PointerProperty,
10 from bpy.types import (
11 PropertyGroup,
12 AddonPreferences,
16 bl_info = {
17 "name": "3D Viewport Pie Menus",
18 "author": "meta-androcto",
19 "version": (1, 2, 9),
20 "blender": (2, 80, 0),
21 "description": "Pie Menu Activation",
22 "location": "Addons Preferences",
23 "warning": "",
24 "doc_url": "{BLENDER_MANUAL_URL}/addons/interface/viewport_pies.html",
25 "category": "Interface"
28 sub_modules_names = (
29 "pie_modes_menu",
30 "pie_views_numpad_menu",
31 "pie_sculpt_menu",
32 "pie_origin",
33 "pie_manipulator_menu",
34 "pie_shading_menu",
35 "pie_align_menu",
36 "pie_delete_menu",
37 "pie_apply_transform_menu",
38 "pie_select_menu",
39 "pie_animation_menu",
40 "pie_save_open_menu",
41 "pie_editor_switch_menu",
42 "pie_defaults_menu",
43 "pie_proportional_menu",
47 sub_modules = [__import__(__package__ + "." + submod, {}, {}, submod) for submod in sub_modules_names]
48 sub_modules.sort(key=lambda mod: (mod.bl_info['category'], mod.bl_info['name']))
51 def _get_pref_class(mod):
52 import inspect
54 for obj in vars(mod).values():
55 if inspect.isclass(obj) and issubclass(obj, PropertyGroup):
56 if hasattr(obj, 'bl_idname') and obj.bl_idname == mod.__name__:
57 return obj
60 def get_addon_preferences(name=''):
61 """Acquisition and registration"""
62 addons = bpy.context.preferences.addons
63 if __name__ not in addons: # wm.read_factory_settings()
64 return None
65 addon_prefs = addons[__name__].preferences
66 if name:
67 if not hasattr(addon_prefs, name):
68 for mod in sub_modules:
69 if mod.__name__.split('.')[-1] == name:
70 cls = _get_pref_class(mod)
71 if cls:
72 prop = PointerProperty(type=cls)
73 create_property(PIEToolsPreferences, name, prop)
74 bpy.utils.unregister_class(PIEToolsPreferences)
75 bpy.utils.register_class(PIEToolsPreferences)
76 return getattr(addon_prefs, name, None)
77 else:
78 return addon_prefs
80 def create_property(cls, name, prop):
81 if not hasattr(cls, '__annotations__'):
82 cls.__annotations__ = dict()
83 cls.__annotations__[name] = prop
86 def register_submodule(mod):
87 mod.register()
88 mod.__addon_enabled__ = True
91 def unregister_submodule(mod):
92 if mod.__addon_enabled__:
93 mod.unregister()
94 mod.__addon_enabled__ = False
96 prefs = get_addon_preferences()
97 name = mod.__name__.split('.')[-1]
98 if hasattr(PIEToolsPreferences, name):
99 delattr(PIEToolsPreferences, name)
100 if prefs:
101 bpy.utils.unregister_class(PIEToolsPreferences)
102 bpy.utils.register_class(PIEToolsPreferences)
103 if name in prefs:
104 del prefs[name]
107 class PIEToolsPreferences(AddonPreferences):
108 bl_idname = __name__
110 def draw(self, context):
111 layout = self.layout
113 for mod in sub_modules:
114 mod_name = mod.__name__.split('.')[-1]
115 info = mod.bl_info
116 column = layout.column()
117 box = column.box()
119 # first stage
120 expand = getattr(self, 'show_expanded_' + mod_name)
121 icon = 'TRIA_DOWN' if expand else 'TRIA_RIGHT'
122 col = box.column()
123 row = col.row()
124 sub = row.row()
125 sub.context_pointer_set('addon_prefs', self)
126 op = sub.operator('wm.context_toggle', text='', icon=icon,
127 emboss=False)
128 op.data_path = 'addon_prefs.show_expanded_' + mod_name
129 sub.label(text='{}: {}'.format(info['category'], info['name']))
130 sub = row.row()
131 sub.alignment = 'RIGHT'
132 if info.get('warning'):
133 sub.label(text='', icon='ERROR')
134 sub.prop(self, 'use_' + mod_name, text='')
136 # The second stage
137 if expand:
138 if info.get('description'):
139 split = col.row().split(factor=0.15)
140 split.label(text='Description:')
141 split.label(text=info['description'])
142 if info.get('location'):
143 split = col.row().split(factor=0.15)
144 split.label(text='Location:')
145 split.label(text=info['location'])
147 if info.get('author'):
148 split = col.row().split(factor=0.15)
149 split.label(text='Author:')
150 split.label(text=info['author'])
152 if info.get('version'):
153 split = col.row().split(factor=0.15)
154 split.label(text='Version:')
155 split.label(text='.'.join(str(x) for x in info['version']),
156 translate=False)
157 if info.get('warning'):
158 split = col.row().split(factor=0.15)
159 split.label(text='Warning:')
160 split.label(text=' ' + info['warning'], icon='ERROR')
162 tot_row = int(bool(info.get('doc_url')))
163 if tot_row:
164 split = col.row().split(factor=0.15)
165 split.label(text='Internet:')
166 if info.get('doc_url'):
167 op = split.operator('wm.url_open',
168 text='Documentation', icon='HELP')
169 op.url = info.get('doc_url')
170 for i in range(4 - tot_row):
171 split.separator()
173 # Details and settings
174 if getattr(self, 'use_' + mod_name):
175 prefs = get_addon_preferences(mod_name)
177 if prefs and hasattr(prefs, 'draw'):
178 box = box.column()
179 prefs.layout = box
180 try:
181 prefs.draw(context)
182 except:
183 import traceback
184 traceback.print_exc()
185 box.label(text='Error (see console)', icon='ERROR')
186 del prefs.layout
188 row = layout.row()
189 row.label(text="End of Pie Menu Activations", icon="FILE_PARENT")
192 for mod in sub_modules:
193 info = mod.bl_info
194 mod_name = mod.__name__.split('.')[-1]
196 def gen_update(mod):
197 def update(self, context):
198 enabled = getattr(self, 'use_' + mod.__name__.split('.')[-1])
199 if enabled:
200 register_submodule(mod)
201 else:
202 unregister_submodule(mod)
203 mod.__addon_enabled__ = enabled
204 return update
206 create_property(
207 PIEToolsPreferences,
208 'use_' + mod_name,
209 BoolProperty(
210 name=info['name'],
211 description=info.get('description', ''),
212 update=gen_update(mod),
213 default=True,
216 create_property(
217 PIEToolsPreferences,
218 'show_expanded_' + mod_name,
219 BoolProperty())
222 classes = (
223 PIEToolsPreferences,
227 def register():
228 for cls in classes:
229 bpy.utils.register_class(cls)
231 prefs = get_addon_preferences()
232 for mod in sub_modules:
233 if not hasattr(mod, '__addon_enabled__'):
234 mod.__addon_enabled__ = False
235 name = mod.__name__.split('.')[-1]
236 if getattr(prefs, 'use_' + name):
237 register_submodule(mod)
240 def unregister():
241 for mod in sub_modules:
242 if mod.__addon_enabled__:
243 unregister_submodule(mod)
245 for cls in reversed(classes):
246 bpy.utils.unregister_class(cls)
249 if __name__ == "__main__":
250 register()