Preferences: Remove warning concerning selection in edit mode with MSAA
[blender.git] / release / scripts / startup / bl_ui / space_userpref.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 import bpy
21 from bpy.types import (
22     Header,
23     Menu,
24     Panel,
25 )
26 from bpy.app.translations import pgettext_iface as iface_
27
28
29 class USERPREF_HT_header(Header):
30     bl_space_type = 'PREFERENCES'
31
32     def draw(self, _context):
33         layout = self.layout
34         layout.operator_context = 'EXEC_AREA'
35
36         layout.template_header()
37
38         layout.separator_spacer()
39
40         layout.operator("wm.save_userpref")
41
42
43 class USERPREF_PT_navigation_bar(Panel):
44     bl_label = "Preferences Navigation"
45     bl_space_type = 'PREFERENCES'
46     bl_region_type = 'NAVIGATION_BAR'
47     bl_options = {'HIDE_HEADER'}
48
49     def draw(self, context):
50         layout = self.layout
51
52         prefs = context.preferences
53
54         col = layout.column()
55
56         col.scale_x = 1.3
57         col.scale_y = 1.3
58         col.prop(prefs, "active_section", expand=True)
59
60
61 class USERPREF_PT_save_preferences(Panel):
62     bl_label = "Save Preferences"
63     bl_space_type = 'PREFERENCES'
64     bl_region_type = 'EXECUTE'
65     bl_options = {'HIDE_HEADER'}
66
67     @classmethod
68     def poll(cls, context):
69         # Hide when header is visible
70         for region in context.area.regions:
71             if region.type == 'HEADER' and region.height <= 1:
72                 return True
73
74         return False
75
76     def draw(self, _context):
77         layout = self.layout
78         layout.operator_context = 'EXEC_AREA'
79
80         layout.scale_x = 1.3
81         layout.scale_y = 1.3
82
83         layout.operator("wm.save_userpref")
84
85
86 class PreferencePanel(Panel):
87     """
88     Base class for panels to center align contents with some horizontal margin.
89     Deriving classes need to implement a ``draw_props(context, layout)`` function.
90     """
91
92     bl_space_type = 'PREFERENCES'
93     bl_region_type = 'WINDOW'
94
95     def draw(self, context):
96         layout = self.layout
97         width = context.region.width
98         ui_scale = context.preferences.system.ui_scale
99
100         layout.use_property_split = True
101         layout.use_property_decorate = False  # No animation.
102
103         row = layout.row()
104         if width > (350 * ui_scale):  # No horizontal margin if region is rather small.
105             row.label()  # Needed so col below is centered.
106
107         col = row.column()
108         col.ui_units_x = 50
109
110         # draw_props implemented by deriving classes.
111         self.draw_props(context, col)
112
113         if width > (350 * ui_scale):  # No horizontal margin if region is rather small.
114             row.label()  # Needed so col above is centered.
115
116
117 class USERPREF_PT_interface_display(PreferencePanel):
118     bl_label = "Display"
119
120     @classmethod
121     def poll(cls, context):
122         prefs = context.preferences
123         return (prefs.active_section == 'INTERFACE')
124
125     def draw_props(self, context, layout):
126         prefs = context.preferences
127         view = prefs.view
128
129         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
130
131         flow.prop(view, "ui_scale", text="Resolution Scale")
132         flow.prop(view, "ui_line_width", text="Line Width")
133
134         layout.separator()
135
136         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
137
138         flow.prop(view, "show_splash", text="Splash Screen")
139         flow.prop(view, "show_tooltips")
140         flow.prop(view, "show_tooltips_python")
141         flow.prop(view, "show_developer_ui")
142         flow.prop(view, "show_large_cursors")
143
144
145 class USERPREF_PT_interface_text(PreferencePanel):
146     bl_label = "Text Rendering"
147     bl_options = {'DEFAULT_CLOSED'}
148
149     @classmethod
150     def poll(cls, context):
151         prefs = context.preferences
152         return (prefs.active_section == 'INTERFACE')
153
154     def draw_props(self, context, layout):
155         prefs = context.preferences
156         view = prefs.view
157
158         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
159
160         flow.prop(view, "use_text_antialiasing", text="Anti-aliasing")
161         sub = flow.column()
162         sub.active = view.use_text_antialiasing
163         sub.prop(view, "text_hinting", text="Hinting")
164
165         flow.prop(view, "font_path_ui")
166         flow.prop(view, "font_path_ui_mono")
167
168
169 class USERPREF_PT_interface_translation(PreferencePanel):
170     bl_label = "Translation"
171
172     @classmethod
173     def poll(cls, context):
174         prefs = context.preferences
175         return (prefs.active_section == 'INTERFACE') and bpy.app.build_options.international
176
177     def draw_header(self, context):
178         prefs = context.preferences
179         view = prefs.view
180
181         self.layout.prop(view, "use_international_fonts", text="")
182
183     def draw_props(self, context, layout):
184         prefs = context.preferences
185         view = prefs.view
186
187         layout.active = view.use_international_fonts
188
189         layout.prop(view, "language")
190
191         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
192
193         flow.prop(view, "use_translate_tooltips", text="Tooltips")
194         flow.prop(view, "use_translate_interface", text="Interface")
195         flow.prop(view, "use_translate_new_dataname", text="New Data")
196
197
198 class USERPREF_PT_interface_editors(PreferencePanel):
199     bl_label = "Editors"
200
201     @classmethod
202     def poll(cls, context):
203         prefs = context.preferences
204         return (prefs.active_section == 'INTERFACE')
205
206     def draw_props(self, context, layout):
207         prefs = context.preferences
208         view = prefs.view
209         system = prefs.system
210
211         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
212
213         flow.prop(system, "use_region_overlap")
214         flow.prop(view, "show_layout_ui", text="Corner Splitting")
215         flow.prop(view, "color_picker_type")
216         flow.row().prop(view, "header_align")
217
218
219 class USERPREF_PT_interface_menus(Panel):
220     bl_space_type = 'PREFERENCES'
221     bl_region_type = 'WINDOW'
222     bl_label = "Menus"
223     bl_options = {'DEFAULT_CLOSED'}
224
225     @classmethod
226     def poll(cls, context):
227         prefs = context.preferences
228         return (prefs.active_section == 'INTERFACE')
229
230     def draw(self, context):
231         pass
232
233
234 class USERPREF_PT_interface_menus_mouse_over(PreferencePanel):
235     bl_label = "Open on Mouse Over"
236     bl_parent_id = "USERPREF_PT_interface_menus"
237
238     def draw_header(self, context):
239         prefs = context.preferences
240         view = prefs.view
241
242         self.layout.prop(view, "use_mouse_over_open", text="")
243
244     def draw_props(self, context, layout):
245         prefs = context.preferences
246         view = prefs.view
247
248         layout.active = view.use_mouse_over_open
249
250         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
251
252         flow.prop(view, "open_toplevel_delay", text="Top Level")
253         flow.prop(view, "open_sublevel_delay", text="Sub Level")
254
255
256 class USERPREF_PT_interface_menus_pie(PreferencePanel):
257     bl_label = "Pie Menus"
258     bl_parent_id = "USERPREF_PT_interface_menus"
259
260     def draw_props(self, context, layout):
261         prefs = context.preferences
262         view = prefs.view
263
264         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
265
266         flow.prop(view, "pie_animation_timeout")
267         flow.prop(view, "pie_tap_timeout")
268         flow.prop(view, "pie_initial_timeout")
269         flow.prop(view, "pie_menu_radius")
270         flow.prop(view, "pie_menu_threshold")
271         flow.prop(view, "pie_menu_confirm")
272
273
274 class USERPREF_PT_edit_objects(Panel):
275     bl_label = "Objects"
276     bl_space_type = 'PREFERENCES'
277     bl_region_type = 'WINDOW'
278
279     @classmethod
280     def poll(cls, context):
281         prefs = context.preferences
282         return (prefs.active_section == 'EDITING')
283
284     def draw(self, context):
285         pass
286
287 class USERPREF_PT_edit_objects_new(PreferencePanel):
288     bl_label = "New Objects"
289     bl_parent_id = "USERPREF_PT_edit_objects"
290
291     def draw_props(self, context, layout):
292         prefs = context.preferences
293         edit = prefs.edit
294
295         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
296
297         flow.prop(edit, "material_link", text="Link Materials to")
298         flow.prop(edit, "object_align", text="Align to")
299         flow.prop(edit, "use_enter_edit_mode", text="Enter Edit Mode")
300
301
302 class USERPREF_PT_edit_objects_duplicate_data(PreferencePanel):
303     bl_label = "Duplicate Data"
304     bl_parent_id = "USERPREF_PT_edit_objects"
305
306     def draw_props(self, context, layout):
307         prefs = context.preferences
308         edit = prefs.edit
309
310         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
311
312         col = flow.column()
313         col.prop(edit, "use_duplicate_action", text="Action")
314         col.prop(edit, "use_duplicate_armature", text="Armature")
315         col.prop(edit, "use_duplicate_curve", text="Curve")
316         # col.prop(edit, "use_duplicate_fcurve", text="F-Curve")
317         col.prop(edit, "use_duplicate_light", text="Light")
318         col = flow.column()
319         col.prop(edit, "use_duplicate_material", text="Material")
320         col.prop(edit, "use_duplicate_mesh", text="Mesh")
321         col.prop(edit, "use_duplicate_metaball", text="Metaball")
322         col.prop(edit, "use_duplicate_particle", text="Particle")
323         col = flow.column()
324         col.prop(edit, "use_duplicate_surface", text="Surface")
325         col.prop(edit, "use_duplicate_text", text="Text")
326         col.prop(edit, "use_duplicate_texture", text="Texture")
327
328
329 class USERPREF_PT_edit_cursor(PreferencePanel):
330     bl_label = "3D Cursor"
331
332     @classmethod
333     def poll(cls, context):
334         prefs = context.preferences
335         return (prefs.active_section == 'EDITING')
336
337     def draw_props(self, context, layout):
338         prefs = context.preferences
339         edit = prefs.edit
340
341         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
342
343         flow.prop(edit, "use_mouse_depth_cursor")
344         flow.prop(edit, "use_cursor_lock_adjust")
345
346
347 class USERPREF_PT_edit_gpencil(PreferencePanel):
348     bl_label = "Grease Pencil"
349     bl_options = {'DEFAULT_CLOSED'}
350
351     @classmethod
352     def poll(cls, context):
353         prefs = context.preferences
354         return (prefs.active_section == 'EDITING')
355
356     def draw_props(self, context, layout):
357         prefs = context.preferences
358         edit = prefs.edit
359
360         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
361
362         flow.prop(edit, "grease_pencil_manhattan_distance", text="Manhattan Distance")
363         flow.prop(edit, "grease_pencil_euclidean_distance", text="Euclidean Distance")
364
365
366 class USERPREF_PT_edit_annotations(PreferencePanel):
367     bl_label = "Annotations"
368
369     @classmethod
370     def poll(cls, context):
371         prefs = context.preferences
372         return (prefs.active_section == 'EDITING')
373
374     def draw_props(self, context, layout):
375         prefs = context.preferences
376         edit = prefs.edit
377
378         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
379
380         flow.prop(edit, "grease_pencil_default_color", text="Default Color")
381         flow.prop(edit, "grease_pencil_eraser_radius", text="Eraser Radius")
382         flow.prop(edit, "use_grease_pencil_simplify_stroke", text="Simplify Stroke")
383
384 class USERPREF_PT_edit_weight_paint(PreferencePanel):
385     bl_label = "Weight Paint"
386     bl_options = {'DEFAULT_CLOSED'}
387
388     @classmethod
389     def poll(cls, context):
390         prefs = context.preferences
391         return (prefs.active_section == 'EDITING')
392
393     def draw_props(self, context, layout):
394         prefs = context.preferences
395         view = prefs.view
396
397         layout.prop(view, "use_weight_color_range", text="Use Custom Colors")
398
399         col = layout.column()
400         col.active = view.use_weight_color_range
401         col.template_color_ramp(view, "weight_color_range", expand=True)
402
403
404 class USERPREF_PT_edit_misc(PreferencePanel):
405     bl_label = "Miscellaneous"
406     bl_options = {'DEFAULT_CLOSED'}
407
408     @classmethod
409     def poll(cls, context):
410         prefs = context.preferences
411         return (prefs.active_section == 'EDITING')
412
413     def draw_props(self, context, layout):
414         prefs = context.preferences
415         edit = prefs.edit
416
417         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
418
419         flow.prop(edit, "sculpt_paint_overlay_color", text="Sculpt Overlay Color")
420         flow.prop(edit, "node_margin", text="Node Auto-offset Margin")
421
422
423 class USERPREF_PT_animation_timeline(PreferencePanel):
424     bl_label = "Timeline"
425
426     @classmethod
427     def poll(cls, context):
428         prefs = context.preferences
429         return (prefs.active_section == 'ANIMATION')
430
431     def draw_props(self, context, layout):
432         prefs = context.preferences
433         view = prefs.view
434         edit = prefs.edit
435
436         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
437         flow.prop(edit, "use_negative_frames")
438
439         layout.separator()
440
441         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
442
443         flow.prop(view, "view2d_grid_spacing_min", text="Minimum Grid Spacing")
444         flow.prop(view, "timecode_style")
445         flow.prop(view, "view_frame_type")
446         if view.view_frame_type == 'SECONDS':
447             flow.prop(view, "view_frame_seconds")
448         elif view.view_frame_type == 'KEYFRAMES':
449             flow.prop(view, "view_frame_keyframes")
450
451
452 class USERPREF_PT_animation_keyframes(PreferencePanel):
453     bl_label = "Keyframes"
454
455     @classmethod
456     def poll(cls, context):
457         prefs = context.preferences
458         return (prefs.active_section == 'ANIMATION')
459
460     def draw_props(self, context, layout):
461         prefs = context.preferences
462         edit = prefs.edit
463
464         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
465
466         flow.prop(edit, "use_visual_keying")
467         flow.prop(edit, "use_keyframe_insert_needed", text="Only Insert Needed")
468
469
470 class USERPREF_PT_animation_autokey(PreferencePanel):
471     bl_label = "Auto-Keyframing"
472     bl_parent_id = "USERPREF_PT_animation_keyframes"
473
474     def draw_props(self, context, layout):
475         prefs = context.preferences
476         edit = prefs.edit
477
478         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
479
480         flow.prop(edit, "use_auto_keying_warning", text="Show Warning")
481         flow.prop(edit, "use_keyframe_insert_available", text="Only Insert Available")
482         flow.prop(edit, "use_auto_keying", text="Enable in New Scenes")
483
484
485 class USERPREF_PT_animation_fcurves(PreferencePanel):
486     bl_label = "F-Curves"
487
488     @classmethod
489     def poll(cls, context):
490         prefs = context.preferences
491         return (prefs.active_section == 'ANIMATION')
492
493     def draw_props(self, context, layout):
494         prefs = context.preferences
495         edit = prefs.edit
496
497         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
498
499         flow.prop(edit, "fcurve_unselected_alpha", text="F-Curve Visibility")
500         flow.prop(edit, "keyframe_new_interpolation_type", text="Default Interpolation")
501         flow.prop(edit, "keyframe_new_handle_type", text="Default Handles")
502         flow.prop(edit, "use_insertkey_xyz_to_rgb", text="XYZ to RGB")
503
504
505 class USERPREF_PT_system_sound(PreferencePanel):
506     bl_label = "Sound"
507
508     @classmethod
509     def poll(cls, context):
510         prefs = context.preferences
511         return (prefs.active_section == 'SYSTEM')
512
513     def draw_props(self, context, layout):
514         prefs = context.preferences
515         system = prefs.system
516
517         layout.prop(system, "audio_device", expand=False)
518
519         sub = layout.grid_flow(row_major=False, columns=0, even_columns=False, even_rows=False, align=False)
520         sub.active = system.audio_device not in {'NONE', 'Null'}
521         sub.prop(system, "audio_channels", text="Channels")
522         sub.prop(system, "audio_mixing_buffer", text="Mixing Buffer")
523         sub.prop(system, "audio_sample_rate", text="Sample Rate")
524         sub.prop(system, "audio_sample_format", text="Sample Format")
525
526
527 class USERPREF_PT_system_cycles_devices(PreferencePanel):
528     bl_label = "Cycles Render Devices"
529
530     @classmethod
531     def poll(cls, context):
532         prefs = context.preferences
533         return (prefs.active_section == 'SYSTEM')
534
535     def draw_props(self, context, layout):
536         prefs = context.preferences
537
538         col = layout.column()
539         col.use_property_split = False
540
541         if bpy.app.build_options.cycles:
542             addon = prefs.addons.get("cycles")
543             if addon is not None:
544                 addon.preferences.draw_impl(col, context)
545             del addon
546
547         # NOTE: Disabled for until GPU side of OpenSubdiv is brought back.
548         # system = prefs.system
549         # if hasattr(system, "opensubdiv_compute_type"):
550         #     col.label(text="OpenSubdiv compute:")
551         #     col.row().prop(system, "opensubdiv_compute_type", text="")
552
553
554 class USERPREF_PT_viewport_display(PreferencePanel):
555     bl_label = "Display"
556
557     @classmethod
558     def poll(cls, context):
559         prefs = context.preferences
560         return (prefs.active_section == 'VIEWPORT')
561
562     def draw_props(self, context, layout):
563         prefs = context.preferences
564         view = prefs.view
565
566         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
567
568         flow.prop(view, "show_object_info", text="Object Info")
569         flow.prop(view, "show_view_name", text="View Name")
570         flow.prop(view, "show_playback_fps", text="Playback FPS")
571
572         layout.separator()
573
574         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
575
576         col = flow.column()
577         col.prop(view, "gizmo_size", text="Gizmo Size")
578         col.prop(view, "object_origin_size")
579         col.separator()
580
581         flow.separator()
582
583         col = flow.column()
584         col.prop(view, "mini_axis_type", text="3D Viewport Axis")
585
586         if view.mini_axis_type == 'MINIMAL':
587             sub = col.column()
588             sub.active = view.mini_axis_type == 'MINIMAL'
589             sub.prop(view, "mini_axis_size", text="Size")
590             sub.prop(view, "mini_axis_brightness", text="Brightness")
591
592
593 class USERPREF_PT_viewport_quality(PreferencePanel):
594     bl_label = "Quality"
595
596     @classmethod
597     def poll(cls, context):
598         prefs = context.preferences
599         return (prefs.active_section == 'VIEWPORT')
600
601     def draw_props(self, context, layout):
602         import sys
603         prefs = context.preferences
604         system = prefs.system
605
606         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
607
608         flow.prop(system, "gpu_viewport_quality")
609         flow.prop(system, "multi_sample", text="Multisampling")
610         flow.prop(system, "gpencil_multi_sample", text="Grease Pencil Multisampling")
611
612
613 class USERPREF_PT_viewport_textures(PreferencePanel):
614     bl_label = "Textures"
615
616     @classmethod
617     def poll(cls, context):
618         prefs = context.preferences
619         return (prefs.active_section == 'VIEWPORT')
620
621     def draw_props(self, context, layout):
622         prefs = context.preferences
623         system = prefs.system
624
625         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
626
627         flow.prop(system, "gl_texture_limit", text="Limit Size")
628         flow.prop(system, "anisotropic_filter")
629         flow.prop(system, "gl_clip_alpha", slider=True)
630         flow.prop(system, "image_draw_method", text="Image Display Method")
631
632
633 class USERPREF_PT_viewport_selection(PreferencePanel):
634     bl_label = "Selection"
635     bl_options = {'DEFAULT_CLOSED'}
636
637     @classmethod
638     def poll(cls, context):
639         prefs = context.preferences
640         return (prefs.active_section == 'VIEWPORT')
641
642     def draw_props(self, context, layout):
643         prefs = context.preferences
644         system = prefs.system
645
646         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
647
648         flow.prop(system, "use_select_pick_depth")
649
650
651 class USERPREF_PT_system_memory(PreferencePanel):
652     bl_label = "Memory & Limits"
653
654     @classmethod
655     def poll(cls, context):
656         prefs = context.preferences
657         return (prefs.active_section == 'SYSTEM')
658
659     def draw_props(self, context, layout):
660         prefs = context.preferences
661         system = prefs.system
662         edit = prefs.edit
663
664         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
665
666         flow.prop(edit, "undo_steps", text="Undo Steps")
667         flow.prop(edit, "undo_memory_limit", text="Undo Memory Limit")
668         flow.prop(edit, "use_global_undo")
669
670         layout.separator()
671
672         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
673
674         flow.prop(system, "memory_cache_limit", text="Sequencer Cache Limit")
675         flow.prop(system, "scrollback", text="Console Scrollback Lines")
676
677         layout.separator()
678
679         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
680
681         flow.prop(system, "texture_time_out", text="Texture Time Out")
682         flow.prop(system, "texture_collection_rate", text="Garbage Collection Rate")
683
684
685 class USERPREF_MT_interface_theme_presets(Menu):
686     bl_label = "Presets"
687     preset_subdir = "interface_theme"
688     preset_operator = "script.execute_preset"
689     preset_type = 'XML'
690     preset_xml_map = (
691         ("preferences.themes[0]", "Theme"),
692         ("preferences.ui_styles[0]", "ThemeStyle"),
693     )
694     draw = Menu.draw_preset
695
696     def reset_cb(context):
697         bpy.ops.ui.reset_default_theme()
698
699
700 class USERPREF_PT_theme(Panel):
701     bl_space_type = 'PREFERENCES'
702     bl_label = "Themes"
703     bl_region_type = 'WINDOW'
704     bl_options = {'HIDE_HEADER'}
705
706     @classmethod
707     def poll(cls, context):
708         prefs = context.preferences
709         return (prefs.active_section == 'THEMES')
710
711     def draw(self, _context):
712         layout = self.layout
713
714         split = layout.split(factor=0.6)
715
716         row = split.row(align=True)
717         row.menu("USERPREF_MT_interface_theme_presets", text=USERPREF_MT_interface_theme_presets.bl_label)
718         row.operator("wm.interface_theme_preset_add", text="", icon='ADD')
719         row.operator("wm.interface_theme_preset_add", text="", icon='REMOVE').remove_active = True
720
721         row = split.row(align=True)
722         row.operator("wm.theme_install", text="Install...", icon='IMPORT')
723         row.operator("ui.reset_default_theme", text="Reset", icon='LOOP_BACK')
724
725
726 class USERPREF_PT_theme_user_interface(PreferencePanel):
727     bl_space_type = 'PREFERENCES'
728     bl_region_type = 'WINDOW'
729     bl_label = "User Interface"
730     bl_options = {'DEFAULT_CLOSED'}
731
732     @classmethod
733     def poll(cls, context):
734         prefs = context.preferences
735         return (prefs.active_section == 'THEMES')
736
737     def draw_header(self, _context):
738         layout = self.layout
739
740         layout.label(icon='WORKSPACE')
741
742     def draw(self, context):
743         pass
744
745
746 # Base class for dynamically defined widget color panels.
747 class PreferenceThemeWidgetColorPanel(Panel):
748     bl_space_type = 'PREFERENCES'
749     bl_region_type = 'WINDOW'
750     bl_parent_id = "USERPREF_PT_theme_user_interface"
751
752     @staticmethod
753     def draw(self, context):
754         theme = context.preferences.themes[0]
755         ui = theme.user_interface
756         widget_style = getattr(ui, self.wcol)
757         layout = self.layout
758
759         layout.use_property_split = True
760
761         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
762
763         col = flow.column()
764         col.prop(widget_style, "outline")
765         col.prop(widget_style, "item", slider=True)
766         col.prop(widget_style, "inner", slider=True)
767         col.prop(widget_style, "inner_sel", slider=True)
768
769         col = flow.column()
770         col.prop(widget_style, "text")
771         col.prop(widget_style, "text_sel")
772         col.prop(widget_style, "roundness")
773
774         col = flow.column()
775         col.prop(widget_style, "show_shaded")
776
777         colsub = col.column()
778         colsub.active = widget_style.show_shaded
779         colsub.prop(widget_style, "shadetop")
780         colsub.prop(widget_style, "shadedown")
781
782     @classmethod
783     def poll(cls, context):
784         prefs = context.preferences
785         return (prefs.active_section == 'THEMES')
786
787
788 class USERPREF_PT_theme_interface_state(PreferencePanel):
789     bl_label = "State"
790     bl_options = {'DEFAULT_CLOSED'}
791     bl_parent_id = "USERPREF_PT_theme_user_interface"
792
793     def draw_props(self, context, layout):
794         theme = context.preferences.themes[0]
795         ui_state = theme.user_interface.wcol_state
796
797         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
798
799         col = flow.column(align=True)
800         col.prop(ui_state, "inner_anim")
801         col.prop(ui_state, "inner_anim_sel")
802
803         col = flow.column(align=True)
804         col.prop(ui_state, "inner_driven")
805         col.prop(ui_state, "inner_driven_sel")
806
807         col = flow.column(align=True)
808         col.prop(ui_state, "inner_key")
809         col.prop(ui_state, "inner_key_sel")
810
811         col = flow.column(align=True)
812         col.prop(ui_state, "inner_overridden")
813         col.prop(ui_state, "inner_overridden_sel")
814
815         col = flow.column(align=True)
816         col.prop(ui_state, "inner_changed")
817         col.prop(ui_state, "inner_changed_sel")
818
819         col = flow.column(align=True)
820         col.prop(ui_state, "blend")
821
822
823 class USERPREF_PT_theme_interface_styles(PreferencePanel):
824     bl_label = "Styles"
825     bl_options = {'DEFAULT_CLOSED'}
826     bl_parent_id = "USERPREF_PT_theme_user_interface"
827
828     def draw_props(self, context, layout):
829         theme = context.preferences.themes[0]
830         ui = theme.user_interface
831
832         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
833
834         flow.prop(ui, "menu_shadow_fac")
835         flow.prop(ui, "icon_alpha")
836         flow.prop(ui, "icon_saturation")
837         flow.prop(ui, "editor_outline")
838         flow.prop(ui, "menu_shadow_width")
839         flow.prop(ui, "widget_emboss")
840
841
842 class USERPREF_PT_theme_interface_gizmos(PreferencePanel):
843     bl_label = "Axis & Gizmo Colors"
844     bl_options = {'DEFAULT_CLOSED'}
845     bl_parent_id = "USERPREF_PT_theme_user_interface"
846
847     def draw_props(self, context, layout):
848         theme = context.preferences.themes[0]
849         ui = theme.user_interface
850
851         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=True, align=False)
852
853         col = flow.column(align=True)
854         col.prop(ui, "axis_x", text="Axis X")
855         col.prop(ui, "axis_y", text="Y")
856         col.prop(ui, "axis_z", text="Z")
857
858         col = flow.column()
859         col.prop(ui, "gizmo_primary")
860         col.prop(ui, "gizmo_secondary")
861
862         col = flow.column()
863         col.prop(ui, "gizmo_a")
864         col.prop(ui, "gizmo_b")
865
866
867 class USERPREF_PT_theme_interface_icons(PreferencePanel):
868     bl_label = "Icon Colors"
869     bl_options = {'DEFAULT_CLOSED'}
870     bl_parent_id = "USERPREF_PT_theme_user_interface"
871
872     def draw_props(self, context, layout):
873         theme = context.preferences.themes[0]
874         ui = theme.user_interface
875
876         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
877
878         flow.prop(ui, "icon_collection")
879         flow.prop(ui, "icon_object")
880         flow.prop(ui, "icon_object_data")
881         flow.prop(ui, "icon_modifier")
882         flow.prop(ui, "icon_shading")
883
884
885 class USERPREF_PT_theme_text_style(PreferencePanel):
886     bl_label = "Text Style"
887     bl_options = {'DEFAULT_CLOSED'}
888
889     @classmethod
890     def poll(cls, context):
891         prefs = context.preferences
892         return (prefs.active_section == 'THEMES')
893
894     @staticmethod
895     def _ui_font_style(layout, font_style):
896         layout.use_property_split = True
897         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
898
899         col = flow.column()
900         col.row().prop(font_style, "font_kerning_style", expand=True)
901         col.prop(font_style, "points")
902
903         col = flow.column(align=True)
904         col.prop(font_style, "shadow_offset_x", text="Shadow Offset X")
905         col.prop(font_style, "shadow_offset_y", text="Y")
906
907         col = flow.column()
908         col.prop(font_style, "shadow")
909         col.prop(font_style, "shadow_alpha")
910         col.prop(font_style, "shadow_value")
911
912     def draw_header(self, _context):
913         layout = self.layout
914
915         layout.label(icon='FONTPREVIEW')
916
917     def draw_props(self, context, layout):
918         style = context.preferences.ui_styles[0]
919
920         layout.label(text="Panel Title")
921         self._ui_font_style(layout, style.panel_title)
922
923         layout.separator()
924
925         layout.label(text="Widget")
926         self._ui_font_style(layout, style.widget)
927
928         layout.separator()
929
930         layout.label(text="Widget Label")
931         self._ui_font_style(layout, style.widget_label)
932
933
934 class USERPREF_PT_theme_bone_color_sets(PreferencePanel):
935     bl_label = "Bone Color Sets"
936     bl_options = {'DEFAULT_CLOSED'}
937
938     @classmethod
939     def poll(cls, context):
940         prefs = context.preferences
941         return (prefs.active_section == 'THEMES')
942
943     def draw_header(self, _context):
944         layout = self.layout
945
946         layout.label(icon='COLOR')
947
948     def draw_props(self, context, layout):
949         theme = context.preferences.themes[0]
950
951         layout.use_property_split = True
952
953         for i, ui in enumerate(theme.bone_color_sets, 1):
954             layout.label(text=iface_(f"Color Set {i:d}"), translate=False)
955
956             flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
957
958             flow.prop(ui, "normal")
959             flow.prop(ui, "select")
960             flow.prop(ui, "active")
961             flow.prop(ui, "show_colored_constraints")
962
963
964 # Base class for dynamically defined theme-space panels.
965 class PreferenceThemeSpacePanel(Panel):
966     bl_space_type = 'PREFERENCES'
967     bl_region_type = 'WINDOW'
968
969     # not essential, hard-coded UI delimiters for the theme layout
970     ui_delimiters = {
971         'VIEW_3D': {
972             "text_grease_pencil",
973             "text_keyframe",
974             "speaker",
975             "freestyle_face_mark",
976             "split_normal",
977             "bone_solid",
978             "paint_curve_pivot",
979         },
980         'GRAPH_EDITOR': {
981             "handle_vertex_select",
982         },
983         'IMAGE_EDITOR': {
984             "paint_curve_pivot",
985         },
986         'NODE_EDITOR': {
987             "layout_node",
988         },
989         'CLIP_EDITOR': {
990             "handle_vertex_select",
991         }
992     }
993
994     # TODO theme_area should be deprecated
995     @staticmethod
996     def _theme_generic(layout, themedata, theme_area):
997
998         layout.use_property_split = True
999
1000         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1001
1002         props_type = {}
1003
1004         for prop in themedata.rna_type.properties:
1005             if prop.identifier == "rna_type":
1006                 continue
1007
1008             props_type.setdefault((prop.type, prop.subtype), []).append(prop)
1009
1010         th_delimiters = PreferenceThemeSpacePanel.ui_delimiters.get(theme_area)
1011         for props_type, props_ls in sorted(props_type.items()):
1012             if props_type[0] == 'POINTER':
1013                 continue
1014
1015             if th_delimiters is None:
1016                 # simple, no delimiters
1017                 for prop in props_ls:
1018                     flow.prop(themedata, prop.identifier)
1019             else:
1020
1021                 for prop in props_ls:
1022                     flow.prop(themedata, prop.identifier)
1023
1024     @staticmethod
1025     def draw_header(self, _context):
1026         if hasattr(self, "icon") and self.icon != 'NONE':
1027             layout = self.layout
1028             layout.label(icon=self.icon)
1029
1030     @staticmethod
1031     def draw(self, context):
1032         layout = self.layout
1033         theme = context.preferences.themes[0]
1034
1035         datapath_list = self.datapath.split(".")
1036         data = theme
1037         for datapath_item in datapath_list:
1038             data = getattr(data, datapath_item)
1039         PreferenceThemeSpacePanel._theme_generic(layout, data, self.theme_area)
1040
1041     @classmethod
1042     def poll(cls, context):
1043         prefs = context.preferences
1044         return (prefs.active_section == 'THEMES')
1045
1046
1047 class ThemeGenericClassGenerator():
1048     generated_classes = []
1049
1050     @staticmethod
1051     def generate_panel_classes_for_wcols():
1052         wcols = [
1053             ("Regular", "wcol_regular"),
1054             ("Tool", "wcol_tool"),
1055             ("Toolbar Item", "wcol_toolbar_item"),
1056             ("Radio Buttons", "wcol_radio"),
1057             ("Text", "wcol_text"),
1058             ("Option", "wcol_option"),
1059             ("Toggle", "wcol_toggle"),
1060             ("Number Field", "wcol_num"),
1061             ("Value Slider", "wcol_numslider"),
1062             ("Box", "wcol_box"),
1063             ("Menu", "wcol_menu"),
1064             ("Pie Menu", "wcol_pie_menu"),
1065             ("Pulldown", "wcol_pulldown"),
1066             ("Menu Back", "wcol_menu_back"),
1067             ("Tooltip", "wcol_tooltip"),
1068             ("Menu Item", "wcol_menu_item"),
1069             ("Scroll Bar", "wcol_scroll"),
1070             ("Progress Bar", "wcol_progress"),
1071             ("List Item", "wcol_list_item"),
1072             ("Tab", "wcol_tab"),
1073         ]
1074
1075         for (name, wcol) in wcols:
1076             panel_id = "USERPREF_PT_theme_interface_" + wcol
1077             paneltype = type(panel_id, (PreferenceThemeWidgetColorPanel,), {
1078                 "bl_label": name,
1079                 "bl_options": {'DEFAULT_CLOSED'},
1080                 "draw": PreferenceThemeWidgetColorPanel.draw,
1081                 "wcol": wcol,
1082             })
1083
1084             ThemeGenericClassGenerator.generated_classes.append(paneltype)
1085
1086     @staticmethod
1087     def generate_theme_area_child_panel_classes(parent_id, rna_type, theme_area, datapath):
1088         def generate_child_panel_classes_recurse(parent_id, rna_type, theme_area, datapath):
1089             props_type = {}
1090
1091             for prop in rna_type.properties:
1092                 if prop.identifier == "rna_type":
1093                     continue
1094
1095                 props_type.setdefault((prop.type, prop.subtype), []).append(prop)
1096
1097             for props_type, props_ls in sorted(props_type.items()):
1098                 if props_type[0] == 'POINTER':
1099                     for prop in props_ls:
1100                         new_datapath = datapath + "." + prop.identifier if datapath else prop.identifier
1101                         panel_id = parent_id + "_" + prop.identifier
1102                         paneltype = type(panel_id, (PreferenceThemeSpacePanel,), {
1103                             "bl_label": rna_type.properties[prop.identifier].name,
1104                             "bl_parent_id": parent_id,
1105                             "bl_options": {'DEFAULT_CLOSED'},
1106                             "draw": PreferenceThemeSpacePanel.draw,
1107                             "theme_area": theme_area.identifier,
1108                             "datapath": new_datapath,
1109                         })
1110
1111                         ThemeGenericClassGenerator.generated_classes.append(paneltype)
1112                         generate_child_panel_classes_recurse(panel_id, prop.fixed_type, theme_area, new_datapath)
1113
1114         generate_child_panel_classes_recurse(parent_id, rna_type, theme_area, datapath)
1115
1116     @staticmethod
1117     def generate_panel_classes_from_theme_areas():
1118         from bpy.types import Theme
1119
1120         for theme_area in Theme.bl_rna.properties['theme_area'].enum_items_static:
1121             if theme_area.identifier in {'USER_INTERFACE', 'STYLE', 'BONE_COLOR_SETS'}:
1122                 continue
1123
1124             panel_id = "USERPREF_PT_theme_" + theme_area.identifier.lower()
1125             # Generate panel-class from theme_area
1126             paneltype = type(panel_id, (PreferenceThemeSpacePanel,), {
1127                 "bl_label": theme_area.name,
1128                 "bl_options": {'DEFAULT_CLOSED'},
1129                 "draw_header": PreferenceThemeSpacePanel.draw_header,
1130                 "draw": PreferenceThemeSpacePanel.draw,
1131                 "theme_area": theme_area.identifier,
1132                 "icon": theme_area.icon,
1133                 "datapath": theme_area.identifier.lower(),
1134             })
1135
1136             ThemeGenericClassGenerator.generated_classes.append(paneltype)
1137             ThemeGenericClassGenerator.generate_theme_area_child_panel_classes(
1138                 panel_id, Theme.bl_rna.properties[theme_area.identifier.lower()].fixed_type,
1139                 theme_area, theme_area.identifier.lower())
1140
1141
1142 class FilePathsPanel(Panel):
1143     bl_space_type = 'PREFERENCES'
1144     bl_region_type = 'WINDOW'
1145
1146     @classmethod
1147     def poll(cls, context):
1148         prefs = context.preferences
1149         return (prefs.active_section == 'FILE_PATHS')
1150
1151     def draw(self, context):
1152         layout = self.layout
1153
1154         layout.use_property_split = True
1155         layout.use_property_decorate = False
1156
1157         self.draw_props(context, layout)
1158
1159
1160 class USERPREF_PT_file_paths_data(FilePathsPanel):
1161     bl_label = "Data"
1162
1163     def draw_props(self, context, layout):
1164         paths = context.preferences.filepaths
1165
1166         col = self.layout.column()
1167         col.prop(paths, "font_directory", text="Fonts")
1168         col.prop(paths, "texture_directory", text="Textures")
1169         col.prop(paths, "script_directory", text="Scripts")
1170         col.prop(paths, "sound_directory", text="Sounds")
1171         col.prop(paths, "temporary_directory", text="Temporary Files")
1172
1173
1174 class USERPREF_PT_file_paths_render(FilePathsPanel):
1175     bl_label = "Render"
1176
1177     def draw_props(self, context, layout):
1178         paths = context.preferences.filepaths
1179
1180         col = self.layout.column()
1181         col.prop(paths, "render_output_directory", text="Render Output")
1182         col.prop(paths, "render_cache_directory", text="Render Cache")
1183
1184
1185 class USERPREF_PT_file_paths_applications(FilePathsPanel):
1186     bl_label = "Applications"
1187
1188     def draw_props(self, context, layout):
1189         paths = context.preferences.filepaths
1190
1191         col = layout.column()
1192         col.prop(paths, "image_editor", text="Image Editor")
1193         col.prop(paths, "animation_player_preset", text="Animation Player")
1194         if paths.animation_player_preset == 'CUSTOM':
1195             col.prop(paths, "animation_player", text="Player")
1196
1197
1198 class USERPREF_PT_file_paths_development(FilePathsPanel):
1199     bl_label = "Development"
1200
1201     @classmethod
1202     def poll(cls, context):
1203         prefs = context.preferences
1204         return (prefs.active_section == 'FILE_PATHS') and prefs.view.show_developer_ui
1205
1206     def draw_props(self, context, layout):
1207         paths = context.preferences.filepaths
1208         layout.prop(paths, "i18n_branches_directory", text="I18n Branches")
1209
1210
1211 class USERPREF_PT_saveload_autorun(PreferencePanel):
1212     bl_label = "Auto Run Python Scripts"
1213     bl_parent_id = "USERPREF_PT_saveload_blend"
1214
1215     def draw_header(self, context):
1216         prefs = context.preferences
1217         paths = prefs.filepaths
1218
1219         self.layout.prop(paths, "use_scripts_auto_execute", text="")
1220
1221     def draw(self, context):
1222         layout = self.layout
1223         prefs = context.preferences
1224         paths = prefs.filepaths
1225
1226         layout.use_property_split = True
1227         layout.use_property_decorate = False  # No animation.
1228
1229         layout.active = paths.use_scripts_auto_execute
1230
1231         box = layout.box()
1232         row = box.row()
1233         row.label(text="Excluded Paths:")
1234         row.operator("wm.userpref_autoexec_path_add", text="", icon='ADD', emboss=False)
1235         for i, path_cmp in enumerate(prefs.autoexec_paths):
1236             row = box.row()
1237             row.prop(path_cmp, "path", text="")
1238             row.prop(path_cmp, "use_glob", text="", icon='FILTER')
1239             row.operator("wm.userpref_autoexec_path_remove", text="", icon='X', emboss=False).index = i
1240
1241
1242 class USERPREF_PT_saveload_blend(PreferencePanel):
1243     bl_label = "Blend Files"
1244
1245     @classmethod
1246     def poll(cls, context):
1247         prefs = context.preferences
1248         return (prefs.active_section == 'SAVE_LOAD')
1249
1250     def draw_props(self, context, layout):
1251         prefs = context.preferences
1252         paths = prefs.filepaths
1253         view = prefs.view
1254
1255         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1256
1257         flow.prop(paths, "use_relative_paths")
1258         flow.prop(paths, "use_file_compression")
1259         flow.prop(paths, "use_load_ui")
1260         flow.prop(paths, "use_save_preview_images")
1261         flow.prop(paths, "use_tabs_as_spaces")
1262         flow.prop(view, "use_save_prompt")
1263
1264         layout.separator()
1265
1266         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1267
1268         flow.prop(paths, "save_version")
1269         flow.prop(paths, "recent_files")
1270
1271
1272 class USERPREF_PT_saveload_blend_autosave(PreferencePanel):
1273     bl_label = "Auto Save"
1274     bl_parent_id = "USERPREF_PT_saveload_blend"
1275
1276     def draw_props(self, context, layout):
1277         prefs = context.preferences
1278         paths = prefs.filepaths
1279
1280         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1281
1282         flow.prop(paths, "use_auto_save_temporary_files")
1283         sub = flow.column()
1284         sub.active = paths.use_auto_save_temporary_files
1285         sub.prop(paths, "auto_save_time", text="Timer (mins)")
1286
1287
1288 class USERPREF_PT_saveload_file_browser(PreferencePanel):
1289     bl_label = "File Browser"
1290
1291     @classmethod
1292     def poll(cls, context):
1293         prefs = context.preferences
1294         return (prefs.active_section == 'SAVE_LOAD')
1295
1296     def draw_props(self, context, layout):
1297         prefs = context.preferences
1298         paths = prefs.filepaths
1299
1300         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1301
1302         flow.prop(paths, "use_filter_files")
1303         flow.prop(paths, "show_hidden_files_datablocks")
1304         flow.prop(paths, "hide_recent_locations")
1305         flow.prop(paths, "hide_system_bookmarks")
1306         flow.prop(paths, "show_thumbnails")
1307
1308
1309 class USERPREF_MT_ndof_settings(Menu):
1310     # accessed from the window key-bindings in C (only)
1311     bl_label = "3D Mouse Settings"
1312
1313     def draw(self, context):
1314         layout = self.layout
1315
1316         input_prefs = context.preferences.inputs
1317
1318         is_view3d = context.space_data.type == 'VIEW_3D'
1319
1320         layout.prop(input_prefs, "ndof_sensitivity")
1321         layout.prop(input_prefs, "ndof_orbit_sensitivity")
1322         layout.prop(input_prefs, "ndof_deadzone")
1323
1324         if is_view3d:
1325             layout.separator()
1326             layout.prop(input_prefs, "ndof_show_guide")
1327
1328             layout.separator()
1329             layout.label(text="Orbit Style")
1330             layout.row().prop(input_prefs, "ndof_view_navigate_method", text="")
1331             layout.row().prop(input_prefs, "ndof_view_rotate_method", text="")
1332             layout.separator()
1333             layout.label(text="Orbit Options")
1334             layout.prop(input_prefs, "ndof_rotx_invert_axis")
1335             layout.prop(input_prefs, "ndof_roty_invert_axis")
1336             layout.prop(input_prefs, "ndof_rotz_invert_axis")
1337
1338         # view2d use pan/zoom
1339         layout.separator()
1340         layout.label(text="Pan Options")
1341         layout.prop(input_prefs, "ndof_panx_invert_axis")
1342         layout.prop(input_prefs, "ndof_pany_invert_axis")
1343         layout.prop(input_prefs, "ndof_panz_invert_axis")
1344         layout.prop(input_prefs, "ndof_pan_yz_swap_axis")
1345
1346         layout.label(text="Zoom Options")
1347         layout.prop(input_prefs, "ndof_zoom_invert")
1348
1349         if is_view3d:
1350             layout.separator()
1351             layout.label(text="Fly/Walk Options")
1352             layout.prop(input_prefs, "ndof_fly_helicopter", icon='NDOF_FLY')
1353             layout.prop(input_prefs, "ndof_lock_horizon", icon='NDOF_DOM')
1354
1355
1356 class USERPREF_PT_input_keyboard(PreferencePanel):
1357     bl_label = "Keyboard"
1358
1359     @classmethod
1360     def poll(cls, context):
1361         prefs = context.preferences
1362         return (prefs.active_section == 'INPUT')
1363
1364     def draw_props(self, context, layout):
1365         prefs = context.preferences
1366         inputs = prefs.inputs
1367
1368         layout.prop(inputs, "use_emulate_numpad")
1369         layout.prop(inputs, "use_numeric_input_advanced")
1370
1371
1372 class USERPREF_PT_input_mouse(PreferencePanel):
1373     bl_label = "Mouse"
1374
1375     @classmethod
1376     def poll(cls, context):
1377         prefs = context.preferences
1378         return (prefs.active_section == 'INPUT')
1379
1380     def draw_props(self, context, layout):
1381         prefs = context.preferences
1382         inputs = prefs.inputs
1383
1384         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1385
1386         flow.prop(inputs, "use_mouse_emulate_3_button")
1387         flow.prop(inputs, "use_mouse_continuous")
1388         flow.prop(inputs, "use_drag_immediately")
1389         flow.prop(inputs, "drag_threshold")
1390         flow.prop(inputs, "mouse_double_click_time", text="Double Click Speed")
1391
1392
1393 class USERPREF_PT_navigation_orbit(PreferencePanel):
1394     bl_label = "Orbit & Pan"
1395
1396     @classmethod
1397     def poll(cls, context):
1398         prefs = context.preferences
1399         return (prefs.active_section == 'NAVIGATION')
1400
1401     def draw_props(self, context, layout):
1402         import sys
1403         prefs = context.preferences
1404         inputs = prefs.inputs
1405         view = prefs.view
1406
1407         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1408
1409         flow.row().prop(inputs, "view_rotate_method", expand=True)
1410         flow.prop(inputs, "use_rotate_around_active")
1411         flow.prop(inputs, "use_auto_perspective")
1412         flow.prop(inputs, "use_mouse_depth_navigate")
1413         if sys.platform == "darwin":
1414             flow.prop(inputs, "use_trackpad_natural", text="Natural Trackpad Direction")
1415
1416         flow.separator()
1417
1418         flow.prop(view, "smooth_view")
1419         flow.prop(view, "rotation_angle")
1420
1421
1422 class USERPREF_PT_navigation_zoom(PreferencePanel):
1423     bl_label = "Zoom"
1424
1425     @classmethod
1426     def poll(cls, context):
1427         prefs = context.preferences
1428         return (prefs.active_section == 'NAVIGATION')
1429
1430     def draw_props(self, context, layout):
1431         prefs = context.preferences
1432         inputs = prefs.inputs
1433
1434         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1435
1436         flow.row().prop(inputs, "view_zoom_method", text="Zoom Method", expand=True)
1437         if inputs.view_zoom_method in {'DOLLY', 'CONTINUE'}:
1438             flow.row().prop(inputs, "view_zoom_axis", expand=True)
1439             flow.prop(inputs, "invert_mouse_zoom", text="Invert Mouse Zoom Direction")
1440
1441         flow.prop(inputs, "invert_zoom_wheel", text="Invert Wheel Zoom Direction")
1442         # sub.prop(view, "wheel_scroll_lines", text="Scroll Lines")
1443         flow.prop(inputs, "use_zoom_to_mouse")
1444
1445
1446 class USERPREF_PT_navigation_fly_walk(PreferencePanel):
1447     bl_label = "Fly & Walk"
1448
1449     @classmethod
1450     def poll(cls, context):
1451         prefs = context.preferences
1452         return (prefs.active_section == 'NAVIGATION')
1453
1454     def draw_props(self, context, layout):
1455         prefs = context.preferences
1456         inputs = prefs.inputs
1457
1458         layout.row().prop(inputs, "navigation_mode", expand=True)
1459
1460         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1461         flow.prop(inputs, "use_camera_lock_parent")
1462
1463
1464 class USERPREF_PT_navigation_fly_walk_navigation(PreferencePanel):
1465     bl_label = "Walk"
1466     bl_parent_id = "USERPREF_PT_navigation_fly_walk"
1467     bl_options = {'DEFAULT_CLOSED'}
1468
1469     @classmethod
1470     def poll(cls, context):
1471         prefs = context.preferences
1472         return prefs.inputs.navigation_mode == 'WALK'
1473
1474     def draw_props(self, context, layout):
1475         prefs = context.preferences
1476         inputs = prefs.inputs
1477         walk = inputs.walk_navigation
1478
1479         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1480
1481         flow.prop(walk, "use_mouse_reverse")
1482         flow.prop(walk, "mouse_speed")
1483         flow.prop(walk, "teleport_time")
1484
1485         sub = flow.column(align=True)
1486         sub.prop(walk, "walk_speed")
1487         sub.prop(walk, "walk_speed_factor")
1488
1489
1490 class USERPREF_PT_navigation_fly_walk_gravity(PreferencePanel):
1491     bl_label = "Gravity"
1492     bl_parent_id = "USERPREF_PT_navigation_fly_walk"
1493     bl_options = {'DEFAULT_CLOSED'}
1494
1495     @classmethod
1496     def poll(cls, context):
1497         prefs = context.preferences
1498         return prefs.inputs.navigation_mode == 'WALK'
1499
1500     def draw_header(self, context):
1501         prefs = context.preferences
1502         inputs = prefs.inputs
1503         walk = inputs.walk_navigation
1504
1505         self.layout.prop(walk, "use_gravity", text="")
1506
1507     def draw_props(self, context, layout):
1508         prefs = context.preferences
1509         inputs = prefs.inputs
1510         walk = inputs.walk_navigation
1511
1512         layout.active = walk.use_gravity
1513
1514         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1515
1516         flow.prop(walk, "view_height")
1517         flow.prop(walk, "jump_height")
1518
1519
1520 class USERPREF_PT_input_tablet(PreferencePanel):
1521     bl_label = "Tablet"
1522
1523     @classmethod
1524     def poll(cls, context):
1525         prefs = context.preferences
1526         inputs = prefs.inputs
1527         return prefs.active_section == 'INPUT'
1528
1529     def draw_props(self, context, layout):
1530         prefs = context.preferences
1531         inputs = prefs.inputs
1532
1533         import sys
1534         if sys.platform[:3] == "win":
1535             layout.prop(inputs, "tablet_api")
1536             layout.separator()
1537
1538         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1539
1540         flow.prop(inputs, "pressure_threshold_max")
1541         flow.prop(inputs, "pressure_softness")
1542
1543
1544 class USERPREF_PT_input_ndof(PreferencePanel):
1545     bl_label = "NDOF"
1546     bl_options = {'DEFAULT_CLOSED'}
1547
1548     @classmethod
1549     def poll(cls, context):
1550         prefs = context.preferences
1551         inputs = prefs.inputs
1552         return prefs.active_section == 'INPUT' and inputs.use_ndof
1553
1554     def draw_props(self, context, layout):
1555         prefs = context.preferences
1556         inputs = prefs.inputs
1557
1558         flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1559
1560         flow.prop(inputs, "ndof_sensitivity", text="Pan Sensitivity")
1561         flow.prop(inputs, "ndof_orbit_sensitivity", text="Orbit Sensitivity")
1562         flow.prop(inputs, "ndof_deadzone", text="Deadzone")
1563
1564         layout.separator()
1565
1566         flow.row().prop(inputs, "ndof_view_navigate_method", expand=True)
1567         flow.row().prop(inputs, "ndof_view_rotate_method", expand=True)
1568
1569
1570 class USERPREF_MT_keyconfigs(Menu):
1571     bl_label = "KeyPresets"
1572     preset_subdir = "keyconfig"
1573     preset_operator = "wm.keyconfig_activate"
1574
1575     def draw(self, context):
1576         Menu.draw_preset(self, context)
1577
1578
1579 class USERPREF_PT_keymap(Panel):
1580     bl_space_type = 'PREFERENCES'
1581     bl_label = "Keymap"
1582     bl_region_type = 'WINDOW'
1583     bl_options = {'HIDE_HEADER'}
1584
1585     @classmethod
1586     def poll(cls, context):
1587         prefs = context.preferences
1588         return (prefs.active_section == 'KEYMAP')
1589
1590     def draw(self, context):
1591         from rna_keymap_ui import draw_keymaps
1592
1593         layout = self.layout
1594
1595         # import time
1596
1597         # start = time.time()
1598
1599         # Keymap Settings
1600         draw_keymaps(context, layout)
1601
1602         # print("runtime", time.time() - start)
1603
1604
1605 class USERPREF_PT_addons(Panel):
1606     bl_space_type = 'PREFERENCES'
1607     bl_label = "Add-ons"
1608     bl_region_type = 'WINDOW'
1609     bl_options = {'HIDE_HEADER'}
1610
1611     _support_icon_mapping = {
1612         'OFFICIAL': 'FILE_BLEND',
1613         'COMMUNITY': 'COMMUNITY',
1614         'TESTING': 'EXPERIMENTAL',
1615     }
1616
1617     @classmethod
1618     def poll(cls, context):
1619         prefs = context.preferences
1620         return (prefs.active_section == 'ADDONS')
1621
1622     @staticmethod
1623     def is_user_addon(mod, user_addon_paths):
1624         import os
1625
1626         if not user_addon_paths:
1627             for path in (
1628                     bpy.utils.script_path_user(),
1629                     bpy.utils.script_path_pref(),
1630             ):
1631                 if path is not None:
1632                     user_addon_paths.append(os.path.join(path, "addons"))
1633
1634         for path in user_addon_paths:
1635             if bpy.path.is_subdir(mod.__file__, path):
1636                 return True
1637         return False
1638
1639     @staticmethod
1640     def draw_error(layout, message):
1641         lines = message.split("\n")
1642         box = layout.box()
1643         sub = box.row()
1644         sub.label(text=lines[0])
1645         sub.label(icon='ERROR')
1646         for l in lines[1:]:
1647             box.label(text=l)
1648
1649     def draw(self, context):
1650         import os
1651         import addon_utils
1652
1653         layout = self.layout
1654
1655         prefs = context.preferences
1656         used_ext = {ext.module for ext in prefs.addons}
1657
1658         addon_user_dirs = tuple(
1659             p for p in (
1660                 os.path.join(prefs.filepaths.script_directory, "addons"),
1661                 bpy.utils.user_resource('SCRIPTS', "addons"),
1662             )
1663             if p
1664         )
1665
1666         # Development option for 2.8x, don't show users bundled addons
1667         # unless they have been updated for 2.8x.
1668         # Developers can turn them on with '--debug'
1669         show_official_27x_addons = bpy.app.debug
1670
1671         # collect the categories that can be filtered on
1672         addons = [
1673             (mod, addon_utils.module_bl_info(mod))
1674             for mod in addon_utils.modules(refresh=False)
1675         ]
1676
1677         split = layout.split(factor=0.6)
1678
1679         row = split.row()
1680         row.prop(context.window_manager, "addon_support", expand=True)
1681
1682         row = split.row(align=True)
1683         row.operator("wm.addon_install", icon='IMPORT', text="Install...")
1684         row.operator("wm.addon_refresh", icon='FILE_REFRESH', text="Refresh")
1685
1686         row = layout.row()
1687         row.prop(context.window_manager, "addon_filter", text="")
1688         row.prop(context.window_manager, "addon_search", text="", icon='VIEWZOOM')
1689
1690         col = layout.column()
1691
1692         # set in addon_utils.modules_refresh()
1693         if addon_utils.error_duplicates:
1694             box = col.box()
1695             row = box.row()
1696             row.label(text="Multiple add-ons with the same name found!")
1697             row.label(icon='ERROR')
1698             box.label(text="Delete one of each pair to resolve:")
1699             for (addon_name, addon_file, addon_path) in addon_utils.error_duplicates:
1700                 box.separator()
1701                 sub_col = box.column(align=True)
1702                 sub_col.label(text=addon_name + ":")
1703                 sub_col.label(text="    " + addon_file)
1704                 sub_col.label(text="    " + addon_path)
1705
1706         if addon_utils.error_encoding:
1707             self.draw_error(
1708                 col,
1709                 "One or more addons do not have UTF-8 encoding\n"
1710                 "(see console for details)",
1711             )
1712
1713         filter = context.window_manager.addon_filter
1714         search = context.window_manager.addon_search.lower()
1715         support = context.window_manager.addon_support
1716
1717         # initialized on demand
1718         user_addon_paths = []
1719
1720         for mod, info in addons:
1721             module_name = mod.__name__
1722
1723             is_enabled = module_name in used_ext
1724
1725             if info["support"] not in support:
1726                 continue
1727
1728             # check if addon should be visible with current filters
1729             if (
1730                     (filter == "All") or
1731                     (filter == info["category"]) or
1732                     (filter == "Enabled" and is_enabled) or
1733                     (filter == "Disabled" and not is_enabled) or
1734                     (filter == "User" and (mod.__file__.startswith(addon_user_dirs)))
1735             ):
1736                 if search and search not in info["name"].lower():
1737                     if info["author"]:
1738                         if search not in info["author"].lower():
1739                             continue
1740                     else:
1741                         continue
1742
1743                 # Skip 2.7x add-ons included with Blender, unless in debug mode.
1744                 is_addon_27x = info.get("blender", (0,)) < (2, 80)
1745                 if (
1746                         is_addon_27x and
1747                         (not show_official_27x_addons) and
1748                         (not mod.__file__.startswith(addon_user_dirs))
1749                 ):
1750                     continue
1751
1752                 # Addon UI Code
1753                 col_box = col.column()
1754                 box = col_box.box()
1755                 colsub = box.column()
1756                 row = colsub.row(align=True)
1757
1758                 row.operator(
1759                     "wm.addon_expand",
1760                     icon='DISCLOSURE_TRI_DOWN' if info["show_expanded"] else 'DISCLOSURE_TRI_RIGHT',
1761                     emboss=False,
1762                 ).module = module_name
1763
1764                 row.operator(
1765                     "wm.addon_disable" if is_enabled else "wm.addon_enable",
1766                     icon='CHECKBOX_HLT' if is_enabled else 'CHECKBOX_DEHLT', text="",
1767                     emboss=False,
1768                 ).module = module_name
1769
1770                 sub = row.row()
1771                 sub.active = is_enabled
1772                 sub.label(text="%s: %s" % (info["category"], info["name"]))
1773
1774                 # WARNING: 2.8x exception, may be removed
1775                 # use disabled state for old add-ons, chances are they are broken.
1776                 if is_addon_27x:
1777                     sub.label(text="upgrade to 2.8x required")
1778                     sub.label(icon='ERROR')
1779                 # Remove code above after 2.8x migration is complete.
1780                 elif info["warning"]:
1781                     sub.label(icon='ERROR')
1782
1783                 # icon showing support level.
1784                 sub.label(icon=self._support_icon_mapping.get(info["support"], 'QUESTION'))
1785
1786                 # Expanded UI (only if additional info is available)
1787                 if info["show_expanded"]:
1788                     if info["description"]:
1789                         split = colsub.row().split(factor=0.15)
1790                         split.label(text="Description:")
1791                         split.label(text=info["description"])
1792                     if info["location"]:
1793                         split = colsub.row().split(factor=0.15)
1794                         split.label(text="Location:")
1795                         split.label(text=info["location"])
1796                     if mod:
1797                         split = colsub.row().split(factor=0.15)
1798                         split.label(text="File:")
1799                         split.label(text=mod.__file__, translate=False)
1800                     if info["author"]:
1801                         split = colsub.row().split(factor=0.15)
1802                         split.label(text="Author:")
1803                         split.label(text=info["author"], translate=False)
1804                     if info["version"]:
1805                         split = colsub.row().split(factor=0.15)
1806                         split.label(text="Version:")
1807                         split.label(text=".".join(str(x) for x in info["version"]), translate=False)
1808                     if info["warning"]:
1809                         split = colsub.row().split(factor=0.15)
1810                         split.label(text="Warning:")
1811                         split.label(text="  " + info["warning"], icon='ERROR')
1812
1813                     user_addon = USERPREF_PT_addons.is_user_addon(mod, user_addon_paths)
1814                     tot_row = bool(info["wiki_url"]) + bool(user_addon)
1815
1816                     if tot_row:
1817                         split = colsub.row().split(factor=0.15)
1818                         split.label(text="Internet:")
1819                         sub = split.row()
1820                         if info["wiki_url"]:
1821                             sub.operator(
1822                                 "wm.url_open", text="Documentation", icon='HELP',
1823                             ).url = info["wiki_url"]
1824                         # Only add "Report a Bug" button if tracker_url is set
1825                         # or the add-on is bundled (use official tracker then).
1826                         if info.get("tracker_url") or not user_addon:
1827                             sub.operator(
1828                                 "wm.url_open", text="Report a Bug", icon='URL',
1829                             ).url = info.get(
1830                                 "tracker_url",
1831                                 "https://developer.blender.org/maniphest/task/edit/form/2",
1832                             )
1833                         if user_addon:
1834                             sub.operator(
1835                                 "wm.addon_remove", text="Remove", icon='CANCEL',
1836                             ).module = mod.__name__
1837
1838                     # Show addon user preferences
1839                     if is_enabled:
1840                         addon_preferences = prefs.addons[module_name].preferences
1841                         if addon_preferences is not None:
1842                             draw = getattr(addon_preferences, "draw", None)
1843                             if draw is not None:
1844                                 addon_preferences_class = type(addon_preferences)
1845                                 box_prefs = col_box.box()
1846                                 box_prefs.label(text="Preferences:")
1847                                 addon_preferences_class.layout = box_prefs
1848                                 try:
1849                                     draw(context)
1850                                 except:
1851                                     import traceback
1852                                     traceback.print_exc()
1853                                     box_prefs.label(text="Error (see console)", icon='ERROR')
1854                                 del addon_preferences_class.layout
1855
1856         # Append missing scripts
1857         # First collect scripts that are used but have no script file.
1858         module_names = {mod.__name__ for mod, info in addons}
1859         missing_modules = {ext for ext in used_ext if ext not in module_names}
1860
1861         if missing_modules and filter in {"All", "Enabled"}:
1862             col.column().separator()
1863             col.column().label(text="Missing script files")
1864
1865             module_names = {mod.__name__ for mod, info in addons}
1866             for module_name in sorted(missing_modules):
1867                 is_enabled = module_name in used_ext
1868                 # Addon UI Code
1869                 box = col.column().box()
1870                 colsub = box.column()
1871                 row = colsub.row(align=True)
1872
1873                 row.label(text="", icon='ERROR')
1874
1875                 if is_enabled:
1876                     row.operator(
1877                         "wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False,
1878                     ).module = module_name
1879
1880                 row.label(text=module_name, translate=False)
1881
1882
1883 class StudioLightPanelMixin():
1884     bl_space_type = 'PREFERENCES'
1885     bl_region_type = 'WINDOW'
1886
1887     @classmethod
1888     def poll(cls, context):
1889         prefs = context.preferences
1890         return (prefs.active_section == 'LIGHTS')
1891
1892     def _get_lights(self, prefs):
1893         return [light for light in prefs.studio_lights if light.is_user_defined and light.type == self.sl_type]
1894
1895     def draw(self, context):
1896         layout = self.layout
1897         prefs = context.preferences
1898         lights = self._get_lights(prefs)
1899
1900         self.draw_light_list(layout, lights)
1901
1902     def draw_light_list(self, layout, lights):
1903         if lights:
1904             flow = layout.grid_flow(row_major=False, columns=4, even_columns=True, even_rows=True, align=False)
1905             for studio_light in lights:
1906                 self.draw_studio_light(flow, studio_light)
1907         else:
1908             layout.label(text="No custom {} configured".format(self.bl_label))
1909
1910     def draw_studio_light(self, layout, studio_light):
1911         box = layout.box()
1912         row = box.row()
1913
1914         row.template_icon(layout.icon(studio_light), scale=3.0)
1915         col = row.column()
1916         op = col.operator("wm.studiolight_uninstall", text="", icon='REMOVE')
1917         op.index = studio_light.index
1918
1919         if studio_light.type == 'STUDIO':
1920             op = col.operator("wm.studiolight_copy_settings", text="", icon='IMPORT')
1921             op.index = studio_light.index
1922
1923         box.label(text=studio_light.name)
1924
1925
1926 class USERPREF_PT_studiolight_matcaps(Panel, StudioLightPanelMixin):
1927     bl_label = "MatCaps"
1928     sl_type = 'MATCAP'
1929
1930     def draw_header_preset(self, context):
1931         layout = self.layout
1932         layout.operator("wm.studiolight_install", icon='IMPORT', text="Install...").type = 'MATCAP'
1933         layout.separator()
1934
1935
1936 class USERPREF_PT_studiolight_world(Panel, StudioLightPanelMixin):
1937     bl_label = "LookDev HDRIs"
1938     sl_type = 'WORLD'
1939
1940     def draw_header_preset(self, context):
1941         layout = self.layout
1942         layout.operator("wm.studiolight_install", icon='IMPORT', text="Install...").type = 'WORLD'
1943         layout.separator()
1944
1945
1946 class USERPREF_PT_studiolight_lights(Panel, StudioLightPanelMixin):
1947     bl_label = "Studio Lights"
1948     sl_type = 'STUDIO'
1949
1950     def draw_header_preset(self, context):
1951         layout = self.layout
1952         op = layout.operator("wm.studiolight_install", icon='IMPORT', text="Install...")
1953         op.type = 'STUDIO'
1954         op.filter_glob = ".sl"
1955         layout.separator()
1956
1957
1958 class USERPREF_PT_studiolight_light_editor(Panel):
1959     bl_label = "Editor"
1960     bl_parent_id = "USERPREF_PT_studiolight_lights"
1961     bl_space_type = 'PREFERENCES'
1962     bl_region_type = 'WINDOW'
1963     bl_options = {'DEFAULT_CLOSED'}
1964
1965     def opengl_light_buttons(self, layout, light):
1966
1967         col = layout.column()
1968         col.active = light.use
1969
1970         col.prop(light, "use", text="Use Light")
1971         col.prop(light, "diffuse_color", text="Diffuse")
1972         col.prop(light, "specular_color", text="Specular")
1973         col.prop(light, "smooth")
1974         col.prop(light, "direction")
1975
1976     def draw(self, context):
1977         layout = self.layout
1978
1979         prefs = context.preferences
1980         system = prefs.system
1981
1982         row = layout.row()
1983         row.prop(system, "use_studio_light_edit", toggle=True)
1984         row.operator("wm.studiolight_new", text="Save as Studio light", icon='FILE_TICK')
1985
1986         layout.separator()
1987
1988         layout.use_property_split = True
1989         column = layout.split()
1990         column.active = system.use_studio_light_edit
1991
1992         light = system.solid_lights[0]
1993         colsplit = column.split(factor=0.85)
1994         self.opengl_light_buttons(colsplit, light)
1995
1996         light = system.solid_lights[1]
1997         colsplit = column.split(factor=0.85)
1998         self.opengl_light_buttons(colsplit, light)
1999
2000         light = system.solid_lights[2]
2001         colsplit = column.split(factor=0.85)
2002         self.opengl_light_buttons(colsplit, light)
2003
2004         light = system.solid_lights[3]
2005         self.opengl_light_buttons(column, light)
2006
2007         layout.separator()
2008
2009         layout.prop(system, "light_ambient")
2010
2011
2012 ThemeGenericClassGenerator.generate_panel_classes_for_wcols()
2013
2014 # Order of registration defines order in UI, so dynamically generated classes are 'injected' in the intended order.
2015 classes = (USERPREF_PT_theme_user_interface,) + tuple(ThemeGenericClassGenerator.generated_classes)
2016
2017 classes += (
2018     USERPREF_HT_header,
2019     USERPREF_PT_navigation_bar,
2020     USERPREF_PT_save_preferences,
2021
2022     USERPREF_PT_interface_display,
2023     USERPREF_PT_interface_editors,
2024     USERPREF_PT_interface_translation,
2025     USERPREF_PT_interface_text,
2026     USERPREF_PT_interface_menus,
2027     USERPREF_PT_interface_menus_mouse_over,
2028     USERPREF_PT_interface_menus_pie,
2029
2030     USERPREF_PT_viewport_display,
2031     USERPREF_PT_viewport_quality,
2032     USERPREF_PT_viewport_textures,
2033     USERPREF_PT_viewport_selection,
2034
2035     USERPREF_PT_edit_objects,
2036     USERPREF_PT_edit_objects_new,
2037     USERPREF_PT_edit_objects_duplicate_data,
2038     USERPREF_PT_edit_cursor,
2039     USERPREF_PT_edit_annotations,
2040     USERPREF_PT_edit_weight_paint,
2041     USERPREF_PT_edit_gpencil,
2042     USERPREF_PT_edit_misc,
2043
2044     USERPREF_PT_animation_timeline,
2045     USERPREF_PT_animation_keyframes,
2046     USERPREF_PT_animation_autokey,
2047     USERPREF_PT_animation_fcurves,
2048
2049     USERPREF_PT_system_cycles_devices,
2050     USERPREF_PT_system_memory,
2051     USERPREF_PT_system_sound,
2052
2053     USERPREF_MT_interface_theme_presets,
2054     USERPREF_PT_theme,
2055     USERPREF_PT_theme_interface_state,
2056     USERPREF_PT_theme_interface_styles,
2057     USERPREF_PT_theme_interface_gizmos,
2058     USERPREF_PT_theme_interface_icons,
2059     USERPREF_PT_theme_text_style,
2060     USERPREF_PT_theme_bone_color_sets,
2061
2062     USERPREF_PT_file_paths_data,
2063     USERPREF_PT_file_paths_render,
2064     USERPREF_PT_file_paths_applications,
2065     USERPREF_PT_file_paths_development,
2066
2067     USERPREF_PT_saveload_blend,
2068     USERPREF_PT_saveload_blend_autosave,
2069     USERPREF_PT_saveload_autorun,
2070     USERPREF_PT_saveload_file_browser,
2071
2072     USERPREF_MT_ndof_settings,
2073     USERPREF_MT_keyconfigs,
2074
2075     USERPREF_PT_input_keyboard,
2076     USERPREF_PT_input_mouse,
2077     USERPREF_PT_input_tablet,
2078     USERPREF_PT_input_ndof,
2079     USERPREF_PT_navigation_orbit,
2080     USERPREF_PT_navigation_zoom,
2081     USERPREF_PT_navigation_fly_walk,
2082     USERPREF_PT_navigation_fly_walk_navigation,
2083     USERPREF_PT_navigation_fly_walk_gravity,
2084
2085     USERPREF_PT_keymap,
2086     USERPREF_PT_addons,
2087
2088     USERPREF_PT_studiolight_lights,
2089     USERPREF_PT_studiolight_light_editor,
2090     USERPREF_PT_studiolight_matcaps,
2091     USERPREF_PT_studiolight_world,
2092 )
2093
2094 # Add dynamically generated editor theme panels last, so they show up last in the theme section.
2095 ThemeGenericClassGenerator.generated_classes.clear()
2096 ThemeGenericClassGenerator.generate_panel_classes_from_theme_areas()
2097 classes += tuple(ThemeGenericClassGenerator.generated_classes)
2098
2099 if __name__ == "__main__":  # only for live edit.
2100     from bpy.utils import register_class
2101     for cls in classes:
2102         register_class(cls)