UI: Add 'Developer Tools' section to user preferences

This PR introduces a 'Developer Tools' section of the user preferences,
enabled when the `Developer Extras` option is enabled. This menu will
not be hidden when the release cycle is no longer in alpha, allowing
developers to use this for common debug options instead of having to use
`G.debug_value` and arbitrary values.

This has the benefit of allowing for an ease of debugging in non-alpha
builds as well as being able to use multiple options that would have
been considered exclusive debug options at once.

None of the existing values bound to a specific `G.debug_value` have
been migrated yet.

Pull Request: https://projects.blender.org/blender/blender/pulls/145215
This commit is contained in:
Sean Kim
2025-09-11 23:53:43 +02:00
committed by Sean Kim
parent dacae33cbe
commit 4c2ea47aec
3 changed files with 122 additions and 104 deletions

View File

@@ -2830,114 +2830,45 @@ class USERPREF_PT_studiolight_light_editor(StudioLightPanel, Panel):
# -----------------------------------------------------------------------------
# Experimental Panels
class ExperimentalPanel:
# Also used for "Developer Tools" which are stored in `preferences.experimental` too.
def _draw_experimental_items(layout, preferences, items, url_prefix="https://projects.blender.org"):
experimental = preferences.experimental
layout.use_property_split = False
layout.use_property_decorate = False
for prop_keywords, reference in items:
split = layout.split(factor=0.66)
col = split.split()
col.prop(experimental, **prop_keywords)
if reference:
if type(reference) is tuple:
url_ext = reference[0]
text = reference[1]
else:
url_ext = reference
text = reference
col = split.split()
col.operator("wm.url_open", text=text, icon='URL').url = url_prefix + url_ext
class USERPREF_PT_developer_tools(Panel):
bl_space_type = 'PREFERENCES'
bl_region_type = 'WINDOW'
bl_context = "experimental"
url_prefix = "https://projects.blender.org/"
bl_context = "developer_tools"
bl_label = "Debug"
@classmethod
def poll(cls, _context):
return bpy.app.version_cycle == "alpha"
def _draw_items(self, context, items):
prefs = context.preferences
experimental = prefs.experimental
layout = self.layout
layout.use_property_split = False
layout.use_property_decorate = False
for prop_keywords, reference in items:
split = layout.split(factor=0.66)
col = split.split()
col.prop(experimental, **prop_keywords)
if reference:
if type(reference) is tuple:
url_ext = reference[0]
text = reference[1]
else:
url_ext = reference
text = reference
col = split.split()
col.operator("wm.url_open", text=text, icon='URL').url = self.url_prefix + url_ext
"""
# Example panel, leave it here so we always have a template to follow even
# after the features are gone from the experimental panel.
class USERPREF_PT_experimental_virtual_reality(ExperimentalPanel, Panel):
bl_label = "Virtual Reality"
def poll(cls, context):
return context.preferences.view.show_developer_ui
def draw(self, context):
self._draw_items(
context, (
({"property": "use_virtual_reality_scene_inspection"}, ("blender/blender/issues/71347", "#71347")),
({"property": "use_virtual_reality_immersive_drawing"}, ("blender/blender/issues/71348", "#71348")),
),
)
"""
class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
bl_label = "New Features"
def draw(self, context):
self._draw_items(
context, (
({"property": "use_extended_asset_browser"},
("blender/blender/projects/10", "Pipeline, Assets & IO Project Page")),
({"property": "use_new_volume_nodes"}, ("blender/blender/issues/103248", "#103248")),
({"property": "use_shader_node_previews"}, ("blender/blender/issues/110353", "#110353")),
({"property": "use_geometry_nodes_lists"}, ("blender/blender/issues/140918", "#140918")),
),
)
class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
bl_label = "Prototypes"
def draw(self, context):
self._draw_items(
context, (
({"property": "use_new_curves_tools"}, ("blender/blender/issues/68981", "#68981")),
({"property": "use_sculpt_texture_paint"}, ("blender/blender/issues/96225", "#96225")),
({"property": "write_legacy_blend_file_format"}, ("/blender/blender/issues/129309", "#129309")),
),
)
# Keep this as tweaks can be useful to restore.
"""
class USERPREF_PT_experimental_tweaks(ExperimentalPanel, Panel):
bl_label = "Tweaks"
def draw(self, context):
self._draw_items(
context, (
({"property": "use_select_nearest_on_first_click"}, ("blender/blender/issues/96752", "#96752")),
),
)
"""
class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel):
bl_label = "Debugging"
@classmethod
def poll(cls, _context):
# Unlike the other experimental panels, the debugging one is always visible
# even in beta or release.
return True
def draw(self, context):
self._draw_items(
context, (
_draw_experimental_items(
self.layout,
context.preferences,
(
({"property": "use_undo_legacy"}, ("blender/blender/issues/60695", "#60695")),
({"property": "override_auto_resync"}, ("blender/blender/issues/83811", "#83811")),
({"property": "use_all_linked_data_direct"}, None),
@@ -2952,6 +2883,83 @@ class USERPREF_PT_experimental_debugging(ExperimentalPanel, Panel):
)
class ExperimentalPanel:
bl_space_type = 'PREFERENCES'
bl_region_type = 'WINDOW'
bl_context = "experimental"
@classmethod
def poll(cls, _context):
return bpy.app.version_cycle == "alpha"
"""
# Example panel, leave it here so we always have a template to follow even
# after the features are gone from the experimental panel.
class USERPREF_PT_experimental_virtual_reality(ExperimentalPanel, Panel):
bl_label = "Virtual Reality"
def draw(self, context):
_draw_experimental_items(
self.layout,
context.preferences,
(
({"property": "use_virtual_reality_scene_inspection"}, ("blender/blender/issues/71347", "#71347")),
({"property": "use_virtual_reality_immersive_drawing"}, ("blender/blender/issues/71348", "#71348")),
),
)
"""
class USERPREF_PT_experimental_new_features(ExperimentalPanel, Panel):
bl_label = "New Features"
def draw(self, context):
_draw_experimental_items(
self.layout,
context.preferences,
(
({"property": "use_extended_asset_browser"},
("blender/blender/projects/10", "Pipeline, Assets & IO Project Page")),
({"property": "use_new_volume_nodes"}, ("blender/blender/issues/103248", "#103248")),
({"property": "use_shader_node_previews"}, ("blender/blender/issues/110353", "#110353")),
({"property": "use_geometry_nodes_lists"}, ("blender/blender/issues/140918", "#140918")),
),
)
class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
bl_label = "Prototypes"
def draw(self, context):
_draw_experimental_items(
self.layout,
context.preferences,
(
({"property": "use_new_curves_tools"}, ("blender/blender/issues/68981", "#68981")),
({"property": "use_sculpt_texture_paint"}, ("blender/blender/issues/96225", "#96225")),
({"property": "write_legacy_blend_file_format"}, ("/blender/blender/issues/129309", "#129309")),
),
)
# Keep this as tweaks can be useful to restore.
"""
class USERPREF_PT_experimental_tweaks(ExperimentalPanel, Panel):
bl_label = "Tweaks"
def draw(self, context):
_draw_experimental_items(
self.layout,
context.preferences,
(
({"property": "use_select_nearest_on_first_click"}, ("blender/blender/issues/96752", "#96752")),
),
)
"""
# -----------------------------------------------------------------------------
# Class Registration
@@ -3067,7 +3075,8 @@ classes = (
USERPREF_PT_experimental_new_features,
USERPREF_PT_experimental_prototypes,
# USERPREF_PT_experimental_tweaks,
USERPREF_PT_experimental_debugging,
USERPREF_PT_developer_tools,
# UI lists
USERPREF_UL_asset_libraries,

View File

@@ -659,6 +659,7 @@ typedef enum eUserPref_Section {
USER_SECTION_FILE_PATHS = 15,
USER_SECTION_EXPERIMENTAL = 16,
USER_SECTION_EXTENSIONS = 17,
USER_SECTION_DEVELOPER_TOOLS = 18,
} eUserPref_Section;
/** #UserDef_SpaceData.flag (State of the user preferences UI). */

View File

@@ -67,6 +67,7 @@ const EnumPropertyItem rna_enum_preference_section_items[] = {
{USER_SECTION_SAVE_LOAD, "SAVE_LOAD", 0, "Save & Load", ""},
{USER_SECTION_FILE_PATHS, "FILE_PATHS", 0, "File Paths", ""},
RNA_ENUM_ITEM_SEPR,
{USER_SECTION_DEVELOPER_TOOLS, "DEVELOPER_TOOLS", 0, "Developer Tools", ""},
{USER_SECTION_EXPERIMENTAL, "EXPERIMENTAL", 0, "Experimental", ""},
{0, nullptr, 0, nullptr, nullptr},
};
@@ -191,6 +192,7 @@ static const EnumPropertyItem rna_enum_preferences_extension_repo_source_type_it
# include "BKE_addon.h"
# include "BKE_appdir.hh"
# include "BKE_blender.hh"
# include "BKE_blender_version.h"
# include "BKE_callbacks.hh"
# include "BKE_global.hh"
# include "BKE_idprop.hh"
@@ -805,8 +807,9 @@ static const EnumPropertyItem *rna_UseDef_active_section_itemf(bContext * /*C*/,
UserDef *userdef = static_cast<UserDef *>(ptr->data);
const bool use_developer_ui = (userdef->flag & USER_DEVELOPER_UI) != 0;
const bool is_alpha = BKE_blender_version_is_alpha();
if (use_developer_ui) {
if (use_developer_ui && is_alpha) {
*r_free = false;
return rna_enum_preference_section_items;
}
@@ -818,6 +821,11 @@ static const EnumPropertyItem *rna_UseDef_active_section_itemf(bContext * /*C*/,
it++)
{
if (it->value == USER_SECTION_EXPERIMENTAL) {
if (is_alpha == false) {
continue;
}
}
else if (it->value == USER_SECTION_DEVELOPER_TOOLS) {
if (use_developer_ui == false) {
continue;
}