1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
21 from bpy.types import (
26 from bpy.app.translations import pgettext_iface as iface_
29 class USERPREF_HT_header(Header):
30 bl_space_type = 'PREFERENCES'
32 def draw(self, _context):
34 layout.operator_context = 'EXEC_AREA'
36 layout.template_header()
38 layout.separator_spacer()
40 layout.operator("wm.save_userpref")
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'}
49 def draw(self, context):
52 prefs = context.preferences
58 col.prop(prefs, "active_section", expand=True)
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'}
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:
76 def draw(self, _context):
78 layout.operator_context = 'EXEC_AREA'
83 layout.operator("wm.save_userpref")
86 class PreferencePanel(Panel):
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.
92 bl_space_type = 'PREFERENCES'
93 bl_region_type = 'WINDOW'
95 def draw(self, context):
97 width = context.region.width
98 ui_scale = context.preferences.system.ui_scale
100 layout.use_property_split = True
101 layout.use_property_decorate = False # No animation.
104 if width > (350 * ui_scale): # No horizontal margin if region is rather small.
105 row.label() # Needed so col below is centered.
110 # draw_props implemented by deriving classes.
111 self.draw_props(context, col)
113 if width > (350 * ui_scale): # No horizontal margin if region is rather small.
114 row.label() # Needed so col above is centered.
117 class USERPREF_PT_interface_display(PreferencePanel):
121 def poll(cls, context):
122 prefs = context.preferences
123 return (prefs.active_section == 'INTERFACE')
125 def draw_props(self, context, layout):
126 prefs = context.preferences
129 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
131 flow.prop(view, "ui_scale", text="Resolution Scale")
132 flow.prop(view, "ui_line_width", text="Line Width")
136 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
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")
145 class USERPREF_PT_interface_text(PreferencePanel):
146 bl_label = "Text Rendering"
147 bl_options = {'DEFAULT_CLOSED'}
150 def poll(cls, context):
151 prefs = context.preferences
152 return (prefs.active_section == 'INTERFACE')
154 def draw_props(self, context, layout):
155 prefs = context.preferences
158 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
160 flow.prop(view, "use_text_antialiasing", text="Anti-aliasing")
162 sub.active = view.use_text_antialiasing
163 sub.prop(view, "text_hinting", text="Hinting")
165 flow.prop(view, "font_path_ui")
166 flow.prop(view, "font_path_ui_mono")
169 class USERPREF_PT_interface_translation(PreferencePanel):
170 bl_label = "Translation"
173 def poll(cls, context):
174 prefs = context.preferences
175 return (prefs.active_section == 'INTERFACE') and bpy.app.build_options.international
177 def draw_header(self, context):
178 prefs = context.preferences
181 self.layout.prop(view, "use_international_fonts", text="")
183 def draw_props(self, context, layout):
184 prefs = context.preferences
187 layout.active = view.use_international_fonts
189 layout.prop(view, "language")
191 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
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")
198 class USERPREF_PT_interface_editors(PreferencePanel):
202 def poll(cls, context):
203 prefs = context.preferences
204 return (prefs.active_section == 'INTERFACE')
206 def draw_props(self, context, layout):
207 prefs = context.preferences
209 system = prefs.system
211 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
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")
219 class USERPREF_PT_interface_menus(Panel):
220 bl_space_type = 'PREFERENCES'
221 bl_region_type = 'WINDOW'
223 bl_options = {'DEFAULT_CLOSED'}
226 def poll(cls, context):
227 prefs = context.preferences
228 return (prefs.active_section == 'INTERFACE')
230 def draw(self, context):
234 class USERPREF_PT_interface_menus_mouse_over(PreferencePanel):
235 bl_label = "Open on Mouse Over"
236 bl_parent_id = "USERPREF_PT_interface_menus"
238 def draw_header(self, context):
239 prefs = context.preferences
242 self.layout.prop(view, "use_mouse_over_open", text="")
244 def draw_props(self, context, layout):
245 prefs = context.preferences
248 layout.active = view.use_mouse_over_open
250 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
252 flow.prop(view, "open_toplevel_delay", text="Top Level")
253 flow.prop(view, "open_sublevel_delay", text="Sub Level")
256 class USERPREF_PT_interface_menus_pie(PreferencePanel):
257 bl_label = "Pie Menus"
258 bl_parent_id = "USERPREF_PT_interface_menus"
260 def draw_props(self, context, layout):
261 prefs = context.preferences
264 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
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")
274 class USERPREF_PT_edit_objects(Panel):
276 bl_space_type = 'PREFERENCES'
277 bl_region_type = 'WINDOW'
280 def poll(cls, context):
281 prefs = context.preferences
282 return (prefs.active_section == 'EDITING')
284 def draw(self, context):
287 class USERPREF_PT_edit_objects_new(PreferencePanel):
288 bl_label = "New Objects"
289 bl_parent_id = "USERPREF_PT_edit_objects"
291 def draw_props(self, context, layout):
292 prefs = context.preferences
295 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
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")
302 class USERPREF_PT_edit_objects_duplicate_data(PreferencePanel):
303 bl_label = "Duplicate Data"
304 bl_parent_id = "USERPREF_PT_edit_objects"
306 def draw_props(self, context, layout):
307 prefs = context.preferences
310 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
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")
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")
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")
329 class USERPREF_PT_edit_cursor(PreferencePanel):
330 bl_label = "3D Cursor"
333 def poll(cls, context):
334 prefs = context.preferences
335 return (prefs.active_section == 'EDITING')
337 def draw_props(self, context, layout):
338 prefs = context.preferences
341 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
343 flow.prop(edit, "use_mouse_depth_cursor")
344 flow.prop(edit, "use_cursor_lock_adjust")
347 class USERPREF_PT_edit_gpencil(PreferencePanel):
348 bl_label = "Grease Pencil"
349 bl_options = {'DEFAULT_CLOSED'}
352 def poll(cls, context):
353 prefs = context.preferences
354 return (prefs.active_section == 'EDITING')
356 def draw_props(self, context, layout):
357 prefs = context.preferences
360 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
362 flow.prop(edit, "grease_pencil_manhattan_distance", text="Manhattan Distance")
363 flow.prop(edit, "grease_pencil_euclidean_distance", text="Euclidean Distance")
366 class USERPREF_PT_edit_annotations(PreferencePanel):
367 bl_label = "Annotations"
370 def poll(cls, context):
371 prefs = context.preferences
372 return (prefs.active_section == 'EDITING')
374 def draw_props(self, context, layout):
375 prefs = context.preferences
378 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
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")
384 class USERPREF_PT_edit_weight_paint(PreferencePanel):
385 bl_label = "Weight Paint"
386 bl_options = {'DEFAULT_CLOSED'}
389 def poll(cls, context):
390 prefs = context.preferences
391 return (prefs.active_section == 'EDITING')
393 def draw_props(self, context, layout):
394 prefs = context.preferences
397 layout.prop(view, "use_weight_color_range", text="Use Custom Colors")
399 col = layout.column()
400 col.active = view.use_weight_color_range
401 col.template_color_ramp(view, "weight_color_range", expand=True)
404 class USERPREF_PT_edit_misc(PreferencePanel):
405 bl_label = "Miscellaneous"
406 bl_options = {'DEFAULT_CLOSED'}
409 def poll(cls, context):
410 prefs = context.preferences
411 return (prefs.active_section == 'EDITING')
413 def draw_props(self, context, layout):
414 prefs = context.preferences
417 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
419 flow.prop(edit, "sculpt_paint_overlay_color", text="Sculpt Overlay Color")
420 flow.prop(edit, "node_margin", text="Node Auto-offset Margin")
423 class USERPREF_PT_animation_timeline(PreferencePanel):
424 bl_label = "Timeline"
427 def poll(cls, context):
428 prefs = context.preferences
429 return (prefs.active_section == 'ANIMATION')
431 def draw_props(self, context, layout):
432 prefs = context.preferences
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")
441 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
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")
452 class USERPREF_PT_animation_keyframes(PreferencePanel):
453 bl_label = "Keyframes"
456 def poll(cls, context):
457 prefs = context.preferences
458 return (prefs.active_section == 'ANIMATION')
460 def draw_props(self, context, layout):
461 prefs = context.preferences
464 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
466 flow.prop(edit, "use_visual_keying")
467 flow.prop(edit, "use_keyframe_insert_needed", text="Only Insert Needed")
470 class USERPREF_PT_animation_autokey(PreferencePanel):
471 bl_label = "Auto-Keyframing"
472 bl_parent_id = "USERPREF_PT_animation_keyframes"
474 def draw_props(self, context, layout):
475 prefs = context.preferences
478 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
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")
485 class USERPREF_PT_animation_fcurves(PreferencePanel):
486 bl_label = "F-Curves"
489 def poll(cls, context):
490 prefs = context.preferences
491 return (prefs.active_section == 'ANIMATION')
493 def draw_props(self, context, layout):
494 prefs = context.preferences
497 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
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")
505 class USERPREF_PT_system_sound(PreferencePanel):
509 def poll(cls, context):
510 prefs = context.preferences
511 return (prefs.active_section == 'SYSTEM')
513 def draw_props(self, context, layout):
514 prefs = context.preferences
515 system = prefs.system
517 layout.prop(system, "audio_device", expand=False)
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")
527 class USERPREF_PT_system_cycles_devices(PreferencePanel):
528 bl_label = "Cycles Render Devices"
531 def poll(cls, context):
532 prefs = context.preferences
533 return (prefs.active_section == 'SYSTEM')
535 def draw_props(self, context, layout):
536 prefs = context.preferences
538 col = layout.column()
539 col.use_property_split = False
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)
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="")
554 class USERPREF_PT_viewport_display(PreferencePanel):
558 def poll(cls, context):
559 prefs = context.preferences
560 return (prefs.active_section == 'VIEWPORT')
562 def draw_props(self, context, layout):
563 prefs = context.preferences
566 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
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")
574 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
577 col.prop(view, "gizmo_size", text="Gizmo Size")
578 col.prop(view, "object_origin_size")
584 col.prop(view, "mini_axis_type", text="3D Viewport Axis")
586 if view.mini_axis_type == 'MINIMAL':
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")
593 class USERPREF_PT_viewport_quality(PreferencePanel):
597 def poll(cls, context):
598 prefs = context.preferences
599 return (prefs.active_section == 'VIEWPORT')
601 def draw_props(self, context, layout):
603 prefs = context.preferences
604 system = prefs.system
606 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
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")
612 if sys.platform == "linux" and system.multi_sample != 'NONE':
613 layout.label(text="Might fail for Mesh editing selection!")
616 class USERPREF_PT_viewport_textures(PreferencePanel):
617 bl_label = "Textures"
620 def poll(cls, context):
621 prefs = context.preferences
622 return (prefs.active_section == 'VIEWPORT')
624 def draw_props(self, context, layout):
625 prefs = context.preferences
626 system = prefs.system
628 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
630 flow.prop(system, "gl_texture_limit", text="Limit Size")
631 flow.prop(system, "anisotropic_filter")
632 flow.prop(system, "gl_clip_alpha", slider=True)
633 flow.prop(system, "image_draw_method", text="Image Display Method")
636 class USERPREF_PT_viewport_selection(PreferencePanel):
637 bl_label = "Selection"
638 bl_options = {'DEFAULT_CLOSED'}
641 def poll(cls, context):
642 prefs = context.preferences
643 return (prefs.active_section == 'VIEWPORT')
645 def draw_props(self, context, layout):
646 prefs = context.preferences
647 system = prefs.system
649 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
651 flow.prop(system, "use_select_pick_depth")
654 class USERPREF_PT_system_memory(PreferencePanel):
655 bl_label = "Memory & Limits"
658 def poll(cls, context):
659 prefs = context.preferences
660 return (prefs.active_section == 'SYSTEM')
662 def draw_props(self, context, layout):
663 prefs = context.preferences
664 system = prefs.system
667 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
669 flow.prop(edit, "undo_steps", text="Undo Steps")
670 flow.prop(edit, "undo_memory_limit", text="Undo Memory Limit")
671 flow.prop(edit, "use_global_undo")
675 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
677 flow.prop(system, "memory_cache_limit", text="Sequencer Cache Limit")
678 flow.prop(system, "scrollback", text="Console Scrollback Lines")
682 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
684 flow.prop(system, "texture_time_out", text="Texture Time Out")
685 flow.prop(system, "texture_collection_rate", text="Garbage Collection Rate")
688 class USERPREF_MT_interface_theme_presets(Menu):
690 preset_subdir = "interface_theme"
691 preset_operator = "script.execute_preset"
694 ("preferences.themes[0]", "Theme"),
695 ("preferences.ui_styles[0]", "ThemeStyle"),
697 draw = Menu.draw_preset
699 def reset_cb(context):
700 bpy.ops.ui.reset_default_theme()
703 class USERPREF_PT_theme(Panel):
704 bl_space_type = 'PREFERENCES'
706 bl_region_type = 'WINDOW'
707 bl_options = {'HIDE_HEADER'}
710 def poll(cls, context):
711 prefs = context.preferences
712 return (prefs.active_section == 'THEMES')
714 def draw(self, _context):
717 split = layout.split(factor=0.6)
719 row = split.row(align=True)
720 row.menu("USERPREF_MT_interface_theme_presets", text=USERPREF_MT_interface_theme_presets.bl_label)
721 row.operator("wm.interface_theme_preset_add", text="", icon='ADD')
722 row.operator("wm.interface_theme_preset_add", text="", icon='REMOVE').remove_active = True
724 row = split.row(align=True)
725 row.operator("wm.theme_install", text="Install...", icon='IMPORT')
726 row.operator("ui.reset_default_theme", text="Reset", icon='LOOP_BACK')
729 class USERPREF_PT_theme_user_interface(PreferencePanel):
730 bl_space_type = 'PREFERENCES'
731 bl_region_type = 'WINDOW'
732 bl_label = "User Interface"
733 bl_options = {'DEFAULT_CLOSED'}
736 def poll(cls, context):
737 prefs = context.preferences
738 return (prefs.active_section == 'THEMES')
740 def draw_header(self, _context):
743 layout.label(icon='WORKSPACE')
745 def draw(self, context):
749 # Base class for dynamically defined widget color panels.
750 class PreferenceThemeWidgetColorPanel(Panel):
751 bl_space_type = 'PREFERENCES'
752 bl_region_type = 'WINDOW'
753 bl_parent_id = "USERPREF_PT_theme_user_interface"
756 def draw(self, context):
757 theme = context.preferences.themes[0]
758 ui = theme.user_interface
759 widget_style = getattr(ui, self.wcol)
762 layout.use_property_split = True
764 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
767 col.prop(widget_style, "outline")
768 col.prop(widget_style, "item", slider=True)
769 col.prop(widget_style, "inner", slider=True)
770 col.prop(widget_style, "inner_sel", slider=True)
773 col.prop(widget_style, "text")
774 col.prop(widget_style, "text_sel")
775 col.prop(widget_style, "roundness")
778 col.prop(widget_style, "show_shaded")
780 colsub = col.column()
781 colsub.active = widget_style.show_shaded
782 colsub.prop(widget_style, "shadetop")
783 colsub.prop(widget_style, "shadedown")
786 def poll(cls, context):
787 prefs = context.preferences
788 return (prefs.active_section == 'THEMES')
791 class USERPREF_PT_theme_interface_state(PreferencePanel):
793 bl_options = {'DEFAULT_CLOSED'}
794 bl_parent_id = "USERPREF_PT_theme_user_interface"
796 def draw_props(self, context, layout):
797 theme = context.preferences.themes[0]
798 ui_state = theme.user_interface.wcol_state
800 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
802 col = flow.column(align=True)
803 col.prop(ui_state, "inner_anim")
804 col.prop(ui_state, "inner_anim_sel")
806 col = flow.column(align=True)
807 col.prop(ui_state, "inner_driven")
808 col.prop(ui_state, "inner_driven_sel")
810 col = flow.column(align=True)
811 col.prop(ui_state, "inner_key")
812 col.prop(ui_state, "inner_key_sel")
814 col = flow.column(align=True)
815 col.prop(ui_state, "inner_overridden")
816 col.prop(ui_state, "inner_overridden_sel")
818 col = flow.column(align=True)
819 col.prop(ui_state, "inner_changed")
820 col.prop(ui_state, "inner_changed_sel")
822 col = flow.column(align=True)
823 col.prop(ui_state, "blend")
826 class USERPREF_PT_theme_interface_styles(PreferencePanel):
828 bl_options = {'DEFAULT_CLOSED'}
829 bl_parent_id = "USERPREF_PT_theme_user_interface"
831 def draw_props(self, context, layout):
832 theme = context.preferences.themes[0]
833 ui = theme.user_interface
835 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
837 flow.prop(ui, "menu_shadow_fac")
838 flow.prop(ui, "icon_alpha")
839 flow.prop(ui, "icon_saturation")
840 flow.prop(ui, "editor_outline")
841 flow.prop(ui, "menu_shadow_width")
842 flow.prop(ui, "widget_emboss")
845 class USERPREF_PT_theme_interface_gizmos(PreferencePanel):
846 bl_label = "Axis & Gizmo Colors"
847 bl_options = {'DEFAULT_CLOSED'}
848 bl_parent_id = "USERPREF_PT_theme_user_interface"
850 def draw_props(self, context, layout):
851 theme = context.preferences.themes[0]
852 ui = theme.user_interface
854 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=True, align=False)
856 col = flow.column(align=True)
857 col.prop(ui, "axis_x", text="Axis X")
858 col.prop(ui, "axis_y", text="Y")
859 col.prop(ui, "axis_z", text="Z")
862 col.prop(ui, "gizmo_primary")
863 col.prop(ui, "gizmo_secondary")
866 col.prop(ui, "gizmo_a")
867 col.prop(ui, "gizmo_b")
870 class USERPREF_PT_theme_interface_icons(PreferencePanel):
871 bl_label = "Icon Colors"
872 bl_options = {'DEFAULT_CLOSED'}
873 bl_parent_id = "USERPREF_PT_theme_user_interface"
875 def draw_props(self, context, layout):
876 theme = context.preferences.themes[0]
877 ui = theme.user_interface
879 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
881 flow.prop(ui, "icon_collection")
882 flow.prop(ui, "icon_object")
883 flow.prop(ui, "icon_object_data")
884 flow.prop(ui, "icon_modifier")
885 flow.prop(ui, "icon_shading")
888 class USERPREF_PT_theme_text_style(PreferencePanel):
889 bl_label = "Text Style"
890 bl_options = {'DEFAULT_CLOSED'}
893 def poll(cls, context):
894 prefs = context.preferences
895 return (prefs.active_section == 'THEMES')
898 def _ui_font_style(layout, font_style):
899 layout.use_property_split = True
900 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
903 col.row().prop(font_style, "font_kerning_style", expand=True)
904 col.prop(font_style, "points")
906 col = flow.column(align=True)
907 col.prop(font_style, "shadow_offset_x", text="Shadow Offset X")
908 col.prop(font_style, "shadow_offset_y", text="Y")
911 col.prop(font_style, "shadow")
912 col.prop(font_style, "shadow_alpha")
913 col.prop(font_style, "shadow_value")
915 def draw_header(self, _context):
918 layout.label(icon='FONTPREVIEW')
920 def draw_props(self, context, layout):
921 style = context.preferences.ui_styles[0]
923 layout.label(text="Panel Title")
924 self._ui_font_style(layout, style.panel_title)
928 layout.label(text="Widget")
929 self._ui_font_style(layout, style.widget)
933 layout.label(text="Widget Label")
934 self._ui_font_style(layout, style.widget_label)
937 class USERPREF_PT_theme_bone_color_sets(PreferencePanel):
938 bl_label = "Bone Color Sets"
939 bl_options = {'DEFAULT_CLOSED'}
942 def poll(cls, context):
943 prefs = context.preferences
944 return (prefs.active_section == 'THEMES')
946 def draw_header(self, _context):
949 layout.label(icon='COLOR')
951 def draw_props(self, context, layout):
952 theme = context.preferences.themes[0]
954 layout.use_property_split = True
956 for i, ui in enumerate(theme.bone_color_sets, 1):
957 layout.label(text=iface_(f"Color Set {i:d}"), translate=False)
959 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
961 flow.prop(ui, "normal")
962 flow.prop(ui, "select")
963 flow.prop(ui, "active")
964 flow.prop(ui, "show_colored_constraints")
967 # Base class for dynamically defined theme-space panels.
968 class PreferenceThemeSpacePanel(Panel):
969 bl_space_type = 'PREFERENCES'
970 bl_region_type = 'WINDOW'
972 # not essential, hard-coded UI delimiters for the theme layout
975 "text_grease_pencil",
978 "freestyle_face_mark",
984 "handle_vertex_select",
993 "handle_vertex_select",
997 # TODO theme_area should be deprecated
999 def _theme_generic(layout, themedata, theme_area):
1001 layout.use_property_split = True
1003 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1007 for prop in themedata.rna_type.properties:
1008 if prop.identifier == "rna_type":
1011 props_type.setdefault((prop.type, prop.subtype), []).append(prop)
1013 th_delimiters = PreferenceThemeSpacePanel.ui_delimiters.get(theme_area)
1014 for props_type, props_ls in sorted(props_type.items()):
1015 if props_type[0] == 'POINTER':
1018 if th_delimiters is None:
1019 # simple, no delimiters
1020 for prop in props_ls:
1021 flow.prop(themedata, prop.identifier)
1024 for prop in props_ls:
1025 flow.prop(themedata, prop.identifier)
1028 def draw_header(self, _context):
1029 if hasattr(self, "icon") and self.icon != 'NONE':
1030 layout = self.layout
1031 layout.label(icon=self.icon)
1034 def draw(self, context):
1035 layout = self.layout
1036 theme = context.preferences.themes[0]
1038 datapath_list = self.datapath.split(".")
1040 for datapath_item in datapath_list:
1041 data = getattr(data, datapath_item)
1042 PreferenceThemeSpacePanel._theme_generic(layout, data, self.theme_area)
1045 def poll(cls, context):
1046 prefs = context.preferences
1047 return (prefs.active_section == 'THEMES')
1050 class ThemeGenericClassGenerator():
1051 generated_classes = []
1054 def generate_panel_classes_for_wcols():
1056 ("Regular", "wcol_regular"),
1057 ("Tool", "wcol_tool"),
1058 ("Toolbar Item", "wcol_toolbar_item"),
1059 ("Radio Buttons", "wcol_radio"),
1060 ("Text", "wcol_text"),
1061 ("Option", "wcol_option"),
1062 ("Toggle", "wcol_toggle"),
1063 ("Number Field", "wcol_num"),
1064 ("Value Slider", "wcol_numslider"),
1065 ("Box", "wcol_box"),
1066 ("Menu", "wcol_menu"),
1067 ("Pie Menu", "wcol_pie_menu"),
1068 ("Pulldown", "wcol_pulldown"),
1069 ("Menu Back", "wcol_menu_back"),
1070 ("Tooltip", "wcol_tooltip"),
1071 ("Menu Item", "wcol_menu_item"),
1072 ("Scroll Bar", "wcol_scroll"),
1073 ("Progress Bar", "wcol_progress"),
1074 ("List Item", "wcol_list_item"),
1075 ("Tab", "wcol_tab"),
1078 for (name, wcol) in wcols:
1079 panel_id = "USERPREF_PT_theme_interface_" + wcol
1080 paneltype = type(panel_id, (PreferenceThemeWidgetColorPanel,), {
1082 "bl_options": {'DEFAULT_CLOSED'},
1083 "draw": PreferenceThemeWidgetColorPanel.draw,
1087 ThemeGenericClassGenerator.generated_classes.append(paneltype)
1090 def generate_theme_area_child_panel_classes(parent_id, rna_type, theme_area, datapath):
1091 def generate_child_panel_classes_recurse(parent_id, rna_type, theme_area, datapath):
1094 for prop in rna_type.properties:
1095 if prop.identifier == "rna_type":
1098 props_type.setdefault((prop.type, prop.subtype), []).append(prop)
1100 for props_type, props_ls in sorted(props_type.items()):
1101 if props_type[0] == 'POINTER':
1102 for prop in props_ls:
1103 new_datapath = datapath + "." + prop.identifier if datapath else prop.identifier
1104 panel_id = parent_id + "_" + prop.identifier
1105 paneltype = type(panel_id, (PreferenceThemeSpacePanel,), {
1106 "bl_label": rna_type.properties[prop.identifier].name,
1107 "bl_parent_id": parent_id,
1108 "bl_options": {'DEFAULT_CLOSED'},
1109 "draw": PreferenceThemeSpacePanel.draw,
1110 "theme_area": theme_area.identifier,
1111 "datapath": new_datapath,
1114 ThemeGenericClassGenerator.generated_classes.append(paneltype)
1115 generate_child_panel_classes_recurse(panel_id, prop.fixed_type, theme_area, new_datapath)
1117 generate_child_panel_classes_recurse(parent_id, rna_type, theme_area, datapath)
1120 def generate_panel_classes_from_theme_areas():
1121 from bpy.types import Theme
1123 for theme_area in Theme.bl_rna.properties['theme_area'].enum_items_static:
1124 if theme_area.identifier in {'USER_INTERFACE', 'STYLE', 'BONE_COLOR_SETS'}:
1127 panel_id = "USERPREF_PT_theme_" + theme_area.identifier.lower()
1128 # Generate panel-class from theme_area
1129 paneltype = type(panel_id, (PreferenceThemeSpacePanel,), {
1130 "bl_label": theme_area.name,
1131 "bl_options": {'DEFAULT_CLOSED'},
1132 "draw_header": PreferenceThemeSpacePanel.draw_header,
1133 "draw": PreferenceThemeSpacePanel.draw,
1134 "theme_area": theme_area.identifier,
1135 "icon": theme_area.icon,
1136 "datapath": theme_area.identifier.lower(),
1139 ThemeGenericClassGenerator.generated_classes.append(paneltype)
1140 ThemeGenericClassGenerator.generate_theme_area_child_panel_classes(
1141 panel_id, Theme.bl_rna.properties[theme_area.identifier.lower()].fixed_type,
1142 theme_area, theme_area.identifier.lower())
1145 class FilePathsPanel(Panel):
1146 bl_space_type = 'PREFERENCES'
1147 bl_region_type = 'WINDOW'
1150 def poll(cls, context):
1151 prefs = context.preferences
1152 return (prefs.active_section == 'FILE_PATHS')
1154 def draw(self, context):
1155 layout = self.layout
1157 layout.use_property_split = True
1158 layout.use_property_decorate = False
1160 self.draw_props(context, layout)
1163 class USERPREF_PT_file_paths_data(FilePathsPanel):
1166 def draw_props(self, context, layout):
1167 paths = context.preferences.filepaths
1169 col = self.layout.column()
1170 col.prop(paths, "font_directory", text="Fonts")
1171 col.prop(paths, "texture_directory", text="Textures")
1172 col.prop(paths, "script_directory", text="Scripts")
1173 col.prop(paths, "sound_directory", text="Sounds")
1174 col.prop(paths, "temporary_directory", text="Temporary Files")
1177 class USERPREF_PT_file_paths_render(FilePathsPanel):
1180 def draw_props(self, context, layout):
1181 paths = context.preferences.filepaths
1183 col = self.layout.column()
1184 col.prop(paths, "render_output_directory", text="Render Output")
1185 col.prop(paths, "render_cache_directory", text="Render Cache")
1188 class USERPREF_PT_file_paths_applications(FilePathsPanel):
1189 bl_label = "Applications"
1191 def draw_props(self, context, layout):
1192 paths = context.preferences.filepaths
1194 col = layout.column()
1195 col.prop(paths, "image_editor", text="Image Editor")
1196 col.prop(paths, "animation_player_preset", text="Animation Player")
1197 if paths.animation_player_preset == 'CUSTOM':
1198 col.prop(paths, "animation_player", text="Player")
1201 class USERPREF_PT_file_paths_development(FilePathsPanel):
1202 bl_label = "Development"
1205 def poll(cls, context):
1206 prefs = context.preferences
1207 return (prefs.active_section == 'FILE_PATHS') and prefs.view.show_developer_ui
1209 def draw_props(self, context, layout):
1210 paths = context.preferences.filepaths
1211 layout.prop(paths, "i18n_branches_directory", text="I18n Branches")
1214 class USERPREF_PT_saveload_autorun(PreferencePanel):
1215 bl_label = "Auto Run Python Scripts"
1216 bl_parent_id = "USERPREF_PT_saveload_blend"
1218 def draw_header(self, context):
1219 prefs = context.preferences
1220 paths = prefs.filepaths
1222 self.layout.prop(paths, "use_scripts_auto_execute", text="")
1224 def draw(self, context):
1225 layout = self.layout
1226 prefs = context.preferences
1227 paths = prefs.filepaths
1229 layout.use_property_split = True
1230 layout.use_property_decorate = False # No animation.
1232 layout.active = paths.use_scripts_auto_execute
1236 row.label(text="Excluded Paths:")
1237 row.operator("wm.userpref_autoexec_path_add", text="", icon='ADD', emboss=False)
1238 for i, path_cmp in enumerate(prefs.autoexec_paths):
1240 row.prop(path_cmp, "path", text="")
1241 row.prop(path_cmp, "use_glob", text="", icon='FILTER')
1242 row.operator("wm.userpref_autoexec_path_remove", text="", icon='X', emboss=False).index = i
1245 class USERPREF_PT_saveload_blend(PreferencePanel):
1246 bl_label = "Blend Files"
1249 def poll(cls, context):
1250 prefs = context.preferences
1251 return (prefs.active_section == 'SAVE_LOAD')
1253 def draw_props(self, context, layout):
1254 prefs = context.preferences
1255 paths = prefs.filepaths
1258 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1260 flow.prop(paths, "use_relative_paths")
1261 flow.prop(paths, "use_file_compression")
1262 flow.prop(paths, "use_load_ui")
1263 flow.prop(paths, "use_save_preview_images")
1264 flow.prop(paths, "use_tabs_as_spaces")
1265 flow.prop(view, "use_quit_dialog")
1269 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1271 flow.prop(paths, "save_version")
1272 flow.prop(paths, "recent_files")
1275 class USERPREF_PT_saveload_blend_autosave(PreferencePanel):
1276 bl_label = "Auto Save"
1277 bl_parent_id = "USERPREF_PT_saveload_blend"
1279 def draw_props(self, context, layout):
1280 prefs = context.preferences
1281 paths = prefs.filepaths
1283 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1285 flow.prop(paths, "use_auto_save_temporary_files")
1287 sub.active = paths.use_auto_save_temporary_files
1288 sub.prop(paths, "auto_save_time", text="Timer (mins)")
1291 class USERPREF_PT_saveload_file_browser(PreferencePanel):
1292 bl_label = "File Browser"
1295 def poll(cls, context):
1296 prefs = context.preferences
1297 return (prefs.active_section == 'SAVE_LOAD')
1299 def draw_props(self, context, layout):
1300 prefs = context.preferences
1301 paths = prefs.filepaths
1303 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1305 flow.prop(paths, "use_filter_files")
1306 flow.prop(paths, "show_hidden_files_datablocks")
1307 flow.prop(paths, "hide_recent_locations")
1308 flow.prop(paths, "hide_system_bookmarks")
1309 flow.prop(paths, "show_thumbnails")
1312 class USERPREF_MT_ndof_settings(Menu):
1313 # accessed from the window key-bindings in C (only)
1314 bl_label = "3D Mouse Settings"
1316 def draw(self, context):
1317 layout = self.layout
1319 input_prefs = context.preferences.inputs
1321 is_view3d = context.space_data.type == 'VIEW_3D'
1323 layout.prop(input_prefs, "ndof_sensitivity")
1324 layout.prop(input_prefs, "ndof_orbit_sensitivity")
1325 layout.prop(input_prefs, "ndof_deadzone")
1329 layout.prop(input_prefs, "ndof_show_guide")
1332 layout.label(text="Orbit Style")
1333 layout.row().prop(input_prefs, "ndof_view_navigate_method", text="")
1334 layout.row().prop(input_prefs, "ndof_view_rotate_method", text="")
1336 layout.label(text="Orbit Options")
1337 layout.prop(input_prefs, "ndof_rotx_invert_axis")
1338 layout.prop(input_prefs, "ndof_roty_invert_axis")
1339 layout.prop(input_prefs, "ndof_rotz_invert_axis")
1341 # view2d use pan/zoom
1343 layout.label(text="Pan Options")
1344 layout.prop(input_prefs, "ndof_panx_invert_axis")
1345 layout.prop(input_prefs, "ndof_pany_invert_axis")
1346 layout.prop(input_prefs, "ndof_panz_invert_axis")
1347 layout.prop(input_prefs, "ndof_pan_yz_swap_axis")
1349 layout.label(text="Zoom Options")
1350 layout.prop(input_prefs, "ndof_zoom_invert")
1354 layout.label(text="Fly/Walk Options")
1355 layout.prop(input_prefs, "ndof_fly_helicopter", icon='NDOF_FLY')
1356 layout.prop(input_prefs, "ndof_lock_horizon", icon='NDOF_DOM')
1359 class USERPREF_PT_input_keyboard(PreferencePanel):
1360 bl_label = "Keyboard"
1363 def poll(cls, context):
1364 prefs = context.preferences
1365 return (prefs.active_section == 'INPUT')
1367 def draw_props(self, context, layout):
1368 prefs = context.preferences
1369 inputs = prefs.inputs
1371 layout.prop(inputs, "use_emulate_numpad")
1372 layout.prop(inputs, "use_numeric_input_advanced")
1375 class USERPREF_PT_input_mouse(PreferencePanel):
1379 def poll(cls, context):
1380 prefs = context.preferences
1381 return (prefs.active_section == 'INPUT')
1383 def draw_props(self, context, layout):
1384 prefs = context.preferences
1385 inputs = prefs.inputs
1387 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1389 flow.prop(inputs, "use_mouse_emulate_3_button")
1390 flow.prop(inputs, "use_mouse_continuous")
1391 flow.prop(inputs, "use_drag_immediately")
1392 flow.prop(inputs, "drag_threshold")
1393 flow.prop(inputs, "mouse_double_click_time", text="Double Click Speed")
1396 class USERPREF_PT_navigation_orbit(PreferencePanel):
1397 bl_label = "Orbit & Pan"
1400 def poll(cls, context):
1401 prefs = context.preferences
1402 return (prefs.active_section == 'NAVIGATION')
1404 def draw_props(self, context, layout):
1406 prefs = context.preferences
1407 inputs = prefs.inputs
1410 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1412 flow.row().prop(inputs, "view_rotate_method", expand=True)
1413 flow.prop(inputs, "use_rotate_around_active")
1414 flow.prop(inputs, "use_auto_perspective")
1415 flow.prop(inputs, "use_mouse_depth_navigate")
1416 if sys.platform == "darwin":
1417 flow.prop(inputs, "use_trackpad_natural", text="Natural Trackpad Direction")
1421 flow.prop(view, "smooth_view")
1422 flow.prop(view, "rotation_angle")
1425 class USERPREF_PT_navigation_zoom(PreferencePanel):
1429 def poll(cls, context):
1430 prefs = context.preferences
1431 return (prefs.active_section == 'NAVIGATION')
1433 def draw_props(self, context, layout):
1434 prefs = context.preferences
1435 inputs = prefs.inputs
1437 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1439 flow.row().prop(inputs, "view_zoom_method", text="Zoom Method", expand=True)
1440 if inputs.view_zoom_method in {'DOLLY', 'CONTINUE'}:
1441 flow.row().prop(inputs, "view_zoom_axis", expand=True)
1442 flow.prop(inputs, "invert_mouse_zoom", text="Invert Mouse Zoom Direction")
1444 flow.prop(inputs, "invert_zoom_wheel", text="Invert Wheel Zoom Direction")
1445 # sub.prop(view, "wheel_scroll_lines", text="Scroll Lines")
1446 flow.prop(inputs, "use_zoom_to_mouse")
1449 class USERPREF_PT_navigation_fly_walk(PreferencePanel):
1450 bl_label = "Fly & Walk"
1453 def poll(cls, context):
1454 prefs = context.preferences
1455 return (prefs.active_section == 'NAVIGATION')
1457 def draw_props(self, context, layout):
1458 prefs = context.preferences
1459 inputs = prefs.inputs
1461 layout.row().prop(inputs, "navigation_mode", expand=True)
1463 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1464 flow.prop(inputs, "use_camera_lock_parent")
1467 class USERPREF_PT_navigation_fly_walk_navigation(PreferencePanel):
1469 bl_parent_id = "USERPREF_PT_navigation_fly_walk"
1470 bl_options = {'DEFAULT_CLOSED'}
1473 def poll(cls, context):
1474 prefs = context.preferences
1475 return prefs.inputs.navigation_mode == 'WALK'
1477 def draw_props(self, context, layout):
1478 prefs = context.preferences
1479 inputs = prefs.inputs
1480 walk = inputs.walk_navigation
1482 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1484 flow.prop(walk, "use_mouse_reverse")
1485 flow.prop(walk, "mouse_speed")
1486 flow.prop(walk, "teleport_time")
1488 sub = flow.column(align=True)
1489 sub.prop(walk, "walk_speed")
1490 sub.prop(walk, "walk_speed_factor")
1493 class USERPREF_PT_navigation_fly_walk_gravity(PreferencePanel):
1494 bl_label = "Gravity"
1495 bl_parent_id = "USERPREF_PT_navigation_fly_walk"
1496 bl_options = {'DEFAULT_CLOSED'}
1499 def poll(cls, context):
1500 prefs = context.preferences
1501 return prefs.inputs.navigation_mode == 'WALK'
1503 def draw_header(self, context):
1504 prefs = context.preferences
1505 inputs = prefs.inputs
1506 walk = inputs.walk_navigation
1508 self.layout.prop(walk, "use_gravity", text="")
1510 def draw_props(self, context, layout):
1511 prefs = context.preferences
1512 inputs = prefs.inputs
1513 walk = inputs.walk_navigation
1515 layout.active = walk.use_gravity
1517 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1519 flow.prop(walk, "view_height")
1520 flow.prop(walk, "jump_height")
1523 class USERPREF_PT_input_tablet(PreferencePanel):
1527 def poll(cls, context):
1528 prefs = context.preferences
1529 inputs = prefs.inputs
1530 return prefs.active_section == 'INPUT'
1532 def draw_props(self, context, layout):
1533 prefs = context.preferences
1534 inputs = prefs.inputs
1537 if sys.platform[:3] == "win":
1538 layout.prop(inputs, "tablet_api")
1541 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1543 flow.prop(inputs, "pressure_threshold_max")
1544 flow.prop(inputs, "pressure_softness")
1547 class USERPREF_PT_input_ndof(PreferencePanel):
1549 bl_options = {'DEFAULT_CLOSED'}
1552 def poll(cls, context):
1553 prefs = context.preferences
1554 inputs = prefs.inputs
1555 return prefs.active_section == 'INPUT' and inputs.use_ndof
1557 def draw_props(self, context, layout):
1558 prefs = context.preferences
1559 inputs = prefs.inputs
1561 flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=False)
1563 flow.prop(inputs, "ndof_sensitivity", text="Pan Sensitivity")
1564 flow.prop(inputs, "ndof_orbit_sensitivity", text="Orbit Sensitivity")
1565 flow.prop(inputs, "ndof_deadzone", text="Deadzone")
1569 flow.row().prop(inputs, "ndof_view_navigate_method", expand=True)
1570 flow.row().prop(inputs, "ndof_view_rotate_method", expand=True)
1573 class USERPREF_MT_keyconfigs(Menu):
1574 bl_label = "KeyPresets"
1575 preset_subdir = "keyconfig"
1576 preset_operator = "wm.keyconfig_activate"
1578 def draw(self, context):
1579 Menu.draw_preset(self, context)
1582 class USERPREF_PT_keymap(Panel):
1583 bl_space_type = 'PREFERENCES'
1585 bl_region_type = 'WINDOW'
1586 bl_options = {'HIDE_HEADER'}
1589 def poll(cls, context):
1590 prefs = context.preferences
1591 return (prefs.active_section == 'KEYMAP')
1593 def draw(self, context):
1594 from rna_keymap_ui import draw_keymaps
1596 layout = self.layout
1600 # start = time.time()
1603 draw_keymaps(context, layout)
1605 # print("runtime", time.time() - start)
1608 class USERPREF_PT_addons(Panel):
1609 bl_space_type = 'PREFERENCES'
1610 bl_label = "Add-ons"
1611 bl_region_type = 'WINDOW'
1612 bl_options = {'HIDE_HEADER'}
1614 _support_icon_mapping = {
1615 'OFFICIAL': 'FILE_BLEND',
1616 'COMMUNITY': 'COMMUNITY',
1617 'TESTING': 'EXPERIMENTAL',
1621 def poll(cls, context):
1622 prefs = context.preferences
1623 return (prefs.active_section == 'ADDONS')
1626 def is_user_addon(mod, user_addon_paths):
1629 if not user_addon_paths:
1631 bpy.utils.script_path_user(),
1632 bpy.utils.script_path_pref(),
1634 if path is not None:
1635 user_addon_paths.append(os.path.join(path, "addons"))
1637 for path in user_addon_paths:
1638 if bpy.path.is_subdir(mod.__file__, path):
1643 def draw_error(layout, message):
1644 lines = message.split("\n")
1647 sub.label(text=lines[0])
1648 sub.label(icon='ERROR')
1652 def draw(self, context):
1656 layout = self.layout
1658 prefs = context.preferences
1659 used_ext = {ext.module for ext in prefs.addons}
1661 addon_user_dirs = tuple(
1663 os.path.join(prefs.filepaths.script_directory, "addons"),
1664 bpy.utils.user_resource('SCRIPTS', "addons"),
1669 # Development option for 2.8x, don't show users bundled addons
1670 # unless they have been updated for 2.8x.
1671 # Developers can turn them on with '--debug'
1672 show_official_27x_addons = bpy.app.debug
1674 # collect the categories that can be filtered on
1676 (mod, addon_utils.module_bl_info(mod))
1677 for mod in addon_utils.modules(refresh=False)
1680 split = layout.split(factor=0.6)
1683 row.prop(context.window_manager, "addon_support", expand=True)
1685 row = split.row(align=True)
1686 row.operator("wm.addon_install", icon='IMPORT', text="Install...")
1687 row.operator("wm.addon_refresh", icon='FILE_REFRESH', text="Refresh")
1690 row.prop(context.window_manager, "addon_filter", text="")
1691 row.prop(context.window_manager, "addon_search", text="", icon='VIEWZOOM')
1693 col = layout.column()
1695 # set in addon_utils.modules_refresh()
1696 if addon_utils.error_duplicates:
1699 row.label(text="Multiple add-ons with the same name found!")
1700 row.label(icon='ERROR')
1701 box.label(text="Delete one of each pair to resolve:")
1702 for (addon_name, addon_file, addon_path) in addon_utils.error_duplicates:
1704 sub_col = box.column(align=True)
1705 sub_col.label(text=addon_name + ":")
1706 sub_col.label(text=" " + addon_file)
1707 sub_col.label(text=" " + addon_path)
1709 if addon_utils.error_encoding:
1712 "One or more addons do not have UTF-8 encoding\n"
1713 "(see console for details)",
1716 filter = context.window_manager.addon_filter
1717 search = context.window_manager.addon_search.lower()
1718 support = context.window_manager.addon_support
1720 # initialized on demand
1721 user_addon_paths = []
1723 for mod, info in addons:
1724 module_name = mod.__name__
1726 is_enabled = module_name in used_ext
1728 if info["support"] not in support:
1731 # check if addon should be visible with current filters
1733 (filter == "All") or
1734 (filter == info["category"]) or
1735 (filter == "Enabled" and is_enabled) or
1736 (filter == "Disabled" and not is_enabled) or
1737 (filter == "User" and (mod.__file__.startswith(addon_user_dirs)))
1739 if search and search not in info["name"].lower():
1741 if search not in info["author"].lower():
1746 # Skip 2.7x add-ons included with Blender, unless in debug mode.
1747 is_addon_27x = info.get("blender", (0,)) < (2, 80)
1750 (not show_official_27x_addons) and
1751 (not mod.__file__.startswith(addon_user_dirs))
1756 col_box = col.column()
1758 colsub = box.column()
1759 row = colsub.row(align=True)
1763 icon='DISCLOSURE_TRI_DOWN' if info["show_expanded"] else 'DISCLOSURE_TRI_RIGHT',
1765 ).module = module_name
1768 "wm.addon_disable" if is_enabled else "wm.addon_enable",
1769 icon='CHECKBOX_HLT' if is_enabled else 'CHECKBOX_DEHLT', text="",
1771 ).module = module_name
1774 sub.active = is_enabled
1775 sub.label(text="%s: %s" % (info["category"], info["name"]))
1777 # WARNING: 2.8x exception, may be removed
1778 # use disabled state for old add-ons, chances are they are broken.
1780 sub.label(text="upgrade to 2.8x required")
1781 sub.label(icon='ERROR')
1782 # Remove code above after 2.8x migration is complete.
1783 elif info["warning"]:
1784 sub.label(icon='ERROR')
1786 # icon showing support level.
1787 sub.label(icon=self._support_icon_mapping.get(info["support"], 'QUESTION'))
1789 # Expanded UI (only if additional info is available)
1790 if info["show_expanded"]:
1791 if info["description"]:
1792 split = colsub.row().split(factor=0.15)
1793 split.label(text="Description:")
1794 split.label(text=info["description"])
1795 if info["location"]:
1796 split = colsub.row().split(factor=0.15)
1797 split.label(text="Location:")
1798 split.label(text=info["location"])
1800 split = colsub.row().split(factor=0.15)
1801 split.label(text="File:")
1802 split.label(text=mod.__file__, translate=False)
1804 split = colsub.row().split(factor=0.15)
1805 split.label(text="Author:")
1806 split.label(text=info["author"], translate=False)
1808 split = colsub.row().split(factor=0.15)
1809 split.label(text="Version:")
1810 split.label(text=".".join(str(x) for x in info["version"]), translate=False)
1812 split = colsub.row().split(factor=0.15)
1813 split.label(text="Warning:")
1814 split.label(text=" " + info["warning"], icon='ERROR')
1816 user_addon = USERPREF_PT_addons.is_user_addon(mod, user_addon_paths)
1817 tot_row = bool(info["wiki_url"]) + bool(user_addon)
1820 split = colsub.row().split(factor=0.15)
1821 split.label(text="Internet:")
1823 if info["wiki_url"]:
1825 "wm.url_open", text="Documentation", icon='HELP',
1826 ).url = info["wiki_url"]
1827 # Only add "Report a Bug" button if tracker_url is set
1828 # or the add-on is bundled (use official tracker then).
1829 if info.get("tracker_url") or not user_addon:
1831 "wm.url_open", text="Report a Bug", icon='URL',
1834 "https://developer.blender.org/maniphest/task/edit/form/2",
1838 "wm.addon_remove", text="Remove", icon='CANCEL',
1839 ).module = mod.__name__
1841 # Show addon user preferences
1843 addon_preferences = prefs.addons[module_name].preferences
1844 if addon_preferences is not None:
1845 draw = getattr(addon_preferences, "draw", None)
1846 if draw is not None:
1847 addon_preferences_class = type(addon_preferences)
1848 box_prefs = col_box.box()
1849 box_prefs.label(text="Preferences:")
1850 addon_preferences_class.layout = box_prefs
1855 traceback.print_exc()
1856 box_prefs.label(text="Error (see console)", icon='ERROR')
1857 del addon_preferences_class.layout
1859 # Append missing scripts
1860 # First collect scripts that are used but have no script file.
1861 module_names = {mod.__name__ for mod, info in addons}
1862 missing_modules = {ext for ext in used_ext if ext not in module_names}
1864 if missing_modules and filter in {"All", "Enabled"}:
1865 col.column().separator()
1866 col.column().label(text="Missing script files")
1868 module_names = {mod.__name__ for mod, info in addons}
1869 for module_name in sorted(missing_modules):
1870 is_enabled = module_name in used_ext
1872 box = col.column().box()
1873 colsub = box.column()
1874 row = colsub.row(align=True)
1876 row.label(text="", icon='ERROR')
1880 "wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False,
1881 ).module = module_name
1883 row.label(text=module_name, translate=False)
1886 class StudioLightPanelMixin():
1887 bl_space_type = 'PREFERENCES'
1888 bl_region_type = 'WINDOW'
1891 def poll(cls, context):
1892 prefs = context.preferences
1893 return (prefs.active_section == 'LIGHTS')
1895 def _get_lights(self, prefs):
1896 return [light for light in prefs.studio_lights if light.is_user_defined and light.type == self.sl_type]
1898 def draw(self, context):
1899 layout = self.layout
1900 prefs = context.preferences
1901 lights = self._get_lights(prefs)
1903 self.draw_light_list(layout, lights)
1905 def draw_light_list(self, layout, lights):
1907 flow = layout.grid_flow(row_major=False, columns=4, even_columns=True, even_rows=True, align=False)
1908 for studio_light in lights:
1909 self.draw_studio_light(flow, studio_light)
1911 layout.label(text="No custom {} configured".format(self.bl_label))
1913 def draw_studio_light(self, layout, studio_light):
1917 row.template_icon(layout.icon(studio_light), scale=3.0)
1919 op = col.operator("wm.studiolight_uninstall", text="", icon='REMOVE')
1920 op.index = studio_light.index
1922 if studio_light.type == 'STUDIO':
1923 op = col.operator("wm.studiolight_copy_settings", text="", icon='IMPORT')
1924 op.index = studio_light.index
1926 box.label(text=studio_light.name)
1929 class USERPREF_PT_studiolight_matcaps(Panel, StudioLightPanelMixin):
1930 bl_label = "MatCaps"
1933 def draw_header_preset(self, context):
1934 layout = self.layout
1935 layout.operator("wm.studiolight_install", icon='IMPORT', text="Install...").type = 'MATCAP'
1939 class USERPREF_PT_studiolight_world(Panel, StudioLightPanelMixin):
1940 bl_label = "LookDev HDRIs"
1943 def draw_header_preset(self, context):
1944 layout = self.layout
1945 layout.operator("wm.studiolight_install", icon='IMPORT', text="Install...").type = 'WORLD'
1949 class USERPREF_PT_studiolight_lights(Panel, StudioLightPanelMixin):
1950 bl_label = "Studio Lights"
1953 def draw_header_preset(self, context):
1954 layout = self.layout
1955 op = layout.operator("wm.studiolight_install", icon='IMPORT', text="Install...")
1957 op.filter_glob = ".sl"
1961 class USERPREF_PT_studiolight_light_editor(Panel):
1963 bl_parent_id = "USERPREF_PT_studiolight_lights"
1964 bl_space_type = 'PREFERENCES'
1965 bl_region_type = 'WINDOW'
1966 bl_options = {'DEFAULT_CLOSED'}
1968 def opengl_light_buttons(self, layout, light):
1970 col = layout.column()
1971 col.active = light.use
1973 col.prop(light, "use", text="Use Light")
1974 col.prop(light, "diffuse_color", text="Diffuse")
1975 col.prop(light, "specular_color", text="Specular")
1976 col.prop(light, "smooth")
1977 col.prop(light, "direction")
1979 def draw(self, context):
1980 layout = self.layout
1982 prefs = context.preferences
1983 system = prefs.system
1986 row.prop(system, "use_studio_light_edit", toggle=True)
1987 row.operator("wm.studiolight_new", text="Save as Studio light", icon='FILE_TICK')
1991 layout.use_property_split = True
1992 column = layout.split()
1993 column.active = system.use_studio_light_edit
1995 light = system.solid_lights[0]
1996 colsplit = column.split(factor=0.85)
1997 self.opengl_light_buttons(colsplit, light)
1999 light = system.solid_lights[1]
2000 colsplit = column.split(factor=0.85)
2001 self.opengl_light_buttons(colsplit, light)
2003 light = system.solid_lights[2]
2004 colsplit = column.split(factor=0.85)
2005 self.opengl_light_buttons(colsplit, light)
2007 light = system.solid_lights[3]
2008 self.opengl_light_buttons(column, light)
2012 layout.prop(system, "light_ambient")
2015 ThemeGenericClassGenerator.generate_panel_classes_for_wcols()
2017 # Order of registration defines order in UI, so dynamically generated classes are 'injected' in the intended order.
2018 classes = (USERPREF_PT_theme_user_interface,) + tuple(ThemeGenericClassGenerator.generated_classes)
2022 USERPREF_PT_navigation_bar,
2023 USERPREF_PT_save_preferences,
2025 USERPREF_PT_interface_display,
2026 USERPREF_PT_interface_editors,
2027 USERPREF_PT_interface_translation,
2028 USERPREF_PT_interface_text,
2029 USERPREF_PT_interface_menus,
2030 USERPREF_PT_interface_menus_mouse_over,
2031 USERPREF_PT_interface_menus_pie,
2033 USERPREF_PT_viewport_display,
2034 USERPREF_PT_viewport_quality,
2035 USERPREF_PT_viewport_textures,
2036 USERPREF_PT_viewport_selection,
2038 USERPREF_PT_edit_objects,
2039 USERPREF_PT_edit_objects_new,
2040 USERPREF_PT_edit_objects_duplicate_data,
2041 USERPREF_PT_edit_cursor,
2042 USERPREF_PT_edit_annotations,
2043 USERPREF_PT_edit_weight_paint,
2044 USERPREF_PT_edit_gpencil,
2045 USERPREF_PT_edit_misc,
2047 USERPREF_PT_animation_timeline,
2048 USERPREF_PT_animation_keyframes,
2049 USERPREF_PT_animation_autokey,
2050 USERPREF_PT_animation_fcurves,
2052 USERPREF_PT_system_cycles_devices,
2053 USERPREF_PT_system_memory,
2054 USERPREF_PT_system_sound,
2056 USERPREF_MT_interface_theme_presets,
2058 USERPREF_PT_theme_interface_state,
2059 USERPREF_PT_theme_interface_styles,
2060 USERPREF_PT_theme_interface_gizmos,
2061 USERPREF_PT_theme_interface_icons,
2062 USERPREF_PT_theme_text_style,
2063 USERPREF_PT_theme_bone_color_sets,
2065 USERPREF_PT_file_paths_data,
2066 USERPREF_PT_file_paths_render,
2067 USERPREF_PT_file_paths_applications,
2068 USERPREF_PT_file_paths_development,
2070 USERPREF_PT_saveload_blend,
2071 USERPREF_PT_saveload_blend_autosave,
2072 USERPREF_PT_saveload_autorun,
2073 USERPREF_PT_saveload_file_browser,
2075 USERPREF_MT_ndof_settings,
2076 USERPREF_MT_keyconfigs,
2078 USERPREF_PT_input_keyboard,
2079 USERPREF_PT_input_mouse,
2080 USERPREF_PT_input_tablet,
2081 USERPREF_PT_input_ndof,
2082 USERPREF_PT_navigation_orbit,
2083 USERPREF_PT_navigation_zoom,
2084 USERPREF_PT_navigation_fly_walk,
2085 USERPREF_PT_navigation_fly_walk_navigation,
2086 USERPREF_PT_navigation_fly_walk_gravity,
2091 USERPREF_PT_studiolight_lights,
2092 USERPREF_PT_studiolight_light_editor,
2093 USERPREF_PT_studiolight_matcaps,
2094 USERPREF_PT_studiolight_world,
2097 # Add dynamically generated editor theme panels last, so they show up last in the theme section.
2098 ThemeGenericClassGenerator.generated_classes.clear()
2099 ThemeGenericClassGenerator.generate_panel_classes_from_theme_areas()
2100 classes += tuple(ThemeGenericClassGenerator.generated_classes)
2102 if __name__ == "__main__": # only for live edit.
2103 from bpy.utils import register_class