1
1

Compare commits

...

47 Commits

Author SHA1 Message Date
TempoDev
11aa61274d Custom Menus : fix build error due to library update 2020-09-04 20:21:56 +02:00
TempoDev
1b8bc74b1f Custom Menus : merge master 2020-09-03 19:37:15 +02:00
TempoDev
705acb423b Custom Menus : fix name of menus items 2020-08-26 03:35:52 +02:00
TempoDev
114987ee42 Custom Menus : fix load from factory preference crash 2020-08-26 01:29:01 +02:00
TempoDev
f8ebfd0e88 Custom Menus : fix idname 2020-08-23 13:29:11 +02:00
TempoDev
0dfe6a6a37 Custom Menus : fix idname change when name change on keymap 2020-08-23 13:21:14 +02:00
TempoDev
fd2d7e7a48 Custom Menus : fix version incompatibility 2020-08-23 11:13:44 +02:00
81aeb7ab08 Quiet const warning 2020-08-19 11:24:10 +10:00
TempoDev
2772910b32 Custom Menus : fix read file 2020-08-16 22:30:55 +02:00
TempoDev
79d256a06d Custom Menus : clean code 2020-08-16 20:06:19 +02:00
TempoDev
278b753088 Merge branch 'soc-2020-custom-menus' of git.blender.org:blender into soc-2020-custom-menus 2020-08-15 03:35:03 +02:00
TempoDev
0137777137 Custom Menus : fix minor bugs 2020-08-14 03:05:34 +02:00
a7e8e509a7 Fix compiler warnings 2020-08-12 18:26:40 +10:00
8da4917156 Merge branch 'master' into soc-2020-custom-menus 2020-08-12 17:58:20 +10:00
TempoDev
4279181f10 Custom Menu : Fix icon edition 2020-08-08 17:41:30 +02:00
TempoDev
b1269effa9 Merge branch 'soc-2020-custom-menus' of git.blender.org:blender into soc-2020-custom-menus 2020-08-07 02:44:26 +02:00
TempoDev
ca64458b61 Custom Menus : change wm.call_user_menu prop index to idname 2020-08-07 02:43:56 +02:00
04ef339f74 Merge branch 'master' into soc-2020-custom-menus 2020-08-05 12:15:02 +10:00
TempoDev
1e68909800 Custom Menus : Add icon edition 2020-08-02 22:33:24 +02:00
TempoDev
0de94b2b62 Custom Menus : add property edition 2020-07-31 23:04:00 +02:00
TempoDev
d225ddec4a Custom Menus : Remove auto keybinding 2020-07-31 22:29:31 +02:00
TempoDev
8d0a3b5c1c Custom Menu : fix add to quick favorite and start property editor 2020-07-31 03:39:49 +02:00
TempoDev
9ca8bf13d5 Custom Menus : merge 2020-07-30 03:22:12 +02:00
TempoDev
2ae9183f4b Custom Menus : fix pie menu buttons 2020-07-30 01:21:01 +02:00
a1dcb2aa70 Merge branch 'master' into soc-2020-custom-menus 2020-07-29 20:35:53 +10:00
9f60b06c8b Quiet compiler warnings 2020-07-29 20:12:54 +10:00
TempoDev
48b5c90975 Custom Menus : Add keymap 2020-07-23 21:22:56 +02:00
TempoDev
1cd405850c Merge : fix conflicts 2020-07-20 03:52:34 +02:00
TempoDev
cd610269dc Custom Menus : add user menus group
You can now create differents menus
2020-07-19 23:49:27 +02:00
TempoDev
9fe9eb5240 Custom Menus: pie menus: pie menu editor 2020-07-06 02:00:48 +02:00
TempoDev
3c9ba5e994 Custom Menus: Add Pie menu 2020-06-30 14:13:42 +02:00
TempoDev
b83e559956 Revert "Custom Menus: Add Pie menu"
This reverts commit fe0e9900d5.
2020-06-30 14:04:20 +02:00
TempoDev
fe0e9900d5 Custom Menus: Add Pie menu 2020-06-29 03:07:21 +02:00
TempoDev
3a519e00c5 Custom Menu: fix merge 2020-06-29 03:06:51 +02:00
TempoDev
2eba146a88 Custom Menu: add submenu item 2020-06-27 17:23:17 +02:00
9c530388ca Merge branch 'master' into soc-2020-custom-menus 2020-06-25 17:11:20 +10:00
TempoDev
bf3c22ec55 Custom Menu: fix merge 2020-06-23 12:38:28 +02:00
TempoDev
7f7a7efc62 Custom Menu: restruct rna and change enum button to button collection 2020-06-23 12:27:22 +02:00
52b2901156 Fix RNA_def_property_enum_funcs use, const cast warning 2020-06-20 16:56:20 +10:00
TempoDev
8344c0acc5 Custom Menus : clean code, rename and minor fix 2020-06-17 19:04:28 +02:00
TempoDev
3229939eae Custom Menu: fix display error, operator editor 2020-06-14 23:36:27 +02:00
TempoDev
d1921a46ca Custom Menu: Add item selection, link add and remove buttons and name edition 2020-06-13 23:27:26 +02:00
TempoDev
b997a7cb51 Custom Menu : Add box and item buttons 2020-06-11 03:07:32 +02:00
TempoDev
8a661f5dd1 Custom Menu: display items of QF in preferences 2020-06-07 19:26:30 +02:00
TempoDev
717dfa198c Custom Menu: link space and context choices to the menus selector 2020-06-06 20:57:32 +02:00
TempoDev
935b518ec7 Custom Menu: link section to panel and add header elements 2020-06-02 16:50:36 +02:00
TempoDev
4e04c9b874 Custom menu: Add section in preference 2020-06-02 16:49:33 +02:00
32 changed files with 2114 additions and 168 deletions

View File

@@ -105,6 +105,7 @@ const UserDef U_default = {
.autoexec_paths = {NULL},
.user_menus = {NULL},
.user_menus_group = {NULL},
.keyconfigstr = "blender",
.undosteps = 32,
@@ -234,5 +235,9 @@ const UserDef U_default = {
.runtime =
{
.is_dirty = 0,
.um_space_select = 1,
.um_context_select = 0,
.um_item_select = NULL,
},
};

View File

@@ -0,0 +1,294 @@
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
__all__ = (
"draw_user_menus",
)
import bpy
from bpy.app.translations import pgettext_iface as iface_
from bpy.app.translations import contexts as i18n_contexts
def _indented_layout(layout, level):
indentpx = 16
if level == 0:
level = 0.0001 # Tweak so that a percentage of 0 won't split by half
indent = level * indentpx / bpy.context.region.width
split = layout.split(factor=indent)
col = split.column()
col = split.column()
return col
def get_keymap(context, idname, ensure):
prefs = context.preferences
um = prefs.user_menus
if not idname:
idname = um.active_group.idname
for km in context.window_manager.keyconfigs.user.keymaps:
for kmi in km.keymap_items:
if kmi.idname == "wm.call_user_menu":
if kmi.properties.name == idname:
return kmi
if ensure:
km = context.window_manager.keyconfigs.user.keymaps['Window']
kmi = km.keymap_items.new("wm.call_user_menu",'NONE', 'ANY', shift=False, ctrl=False, alt=False)
kmi.properties.idname = idname
kmi.active = True
return kmi
def draw_button(context, box, item, index):
prefs = context.preferences
um = prefs.user_menus
name = item.name
if name == "":
name = " "
item.is_selected = item == um.active_item
col = box.column(align=True)
row = col.row(align=True)
if item.type == "SEPARATOR":
name = "___________"
#icons = bpy.types.UILayout.bl_rna.functions["prop"].parameters["icon"].enum_items.keys()
#selected_icon = icons[item.icon]
row.prop(item, "is_selected", icon=item.icon, text=name, toggle=1)
if item.type == "SUBMENU":
sm = item.get_submenu()
if um.active_group.type == "PIE" and index >= 0:
row.operator("preferences.pie_menuitem_add", text="", icon='ADD').index = index
row.operator("preferences.menuitem_remove", text="", icon='REMOVE')
row.operator("preferences.menuitem_up", text="", icon='TRIA_UP')
row.operator("preferences.menuitem_down", text="", icon='TRIA_DOWN')
sub_box = col.box()
sub_box = sub_box.column(align=True)
draw_item(context, sub_box, sm.items_list)
def draw_item(context, box, items):
for umi in items:
draw_button(context, box, umi, -1)
def draw_item_box(context, row):
prefs = context.preferences
um = prefs.user_menus
box_line = row.box()
box_col = box_line.column(align=True)
has_item = um.has_item()
if not has_item:
box_col.label(text="none")
else:
draw_item(context, box_col, um.get_current_menu().menu_items)
row = row.split(factor=0.9, align=True)
col = row.column(align=True)
col.operator("preferences.menuitem_add", text="", icon='ADD').index = -1
col.operator("preferences.menuitem_remove", text="", icon='REMOVE')
col.operator("preferences.menuitem_up", text="", icon='TRIA_UP')
col.operator("preferences.menuitem_down", text="", icon='TRIA_DOWN')
row.separator()
def draw_pie_item(context, col, items, label, index):
row = col.row()
row.label(text=label)
draw_button(context, row, items, index)
def draw_pie(context, row):
prefs = context.preferences
um = prefs.user_menus
cm = um.get_current_menu()
if not cm:
return
col = row.column()
draw_pie_item(context, col, cm.menu_items[0], "Left : ", 0)
draw_pie_item(context, col, cm.menu_items[1], "Right : ", 1)
draw_pie_item(context, col, cm.menu_items[2], "Down : ", 2)
draw_pie_item(context, col, cm.menu_items[3], "Up : ", 3)
draw_pie_item(context, col, cm.menu_items[4], "Upper left : ", 4)
draw_pie_item(context, col, cm.menu_items[5], "Upper right : ", 5)
draw_pie_item(context, col, cm.menu_items[6], "Lower left : ", 6)
draw_pie_item(context, col, cm.menu_items[7], "Lower right : ", 7)
row.separator()
def draw_item_editor(context, row):
prefs = context.preferences
um = prefs.user_menus
col = row.column()
has_item = um.has_item()
current = um.active_item
if not has_item:
col.label(text="No item in this list.")
col.label(text="Add one or choose another list to get started")
elif current:
col.prop(current, "type")
if (current.type != "SEPARATOR"):
rowsub = col.row(align=True)
rowsub.prop(current, "icon", icon=current.icon, text="")
col.prop(current, "name")
if (current.type == "OPERATOR"):
umi_op = current.get_operator()
col.prop(umi_op, "operator")
box = col.box()
box.template_user_menu_item_properties(umi_op)
if (current.type == "MENU"):
umi_pm = current.get_menu()
col.prop(umi_pm, "id_name", text="ID name")
if (current.type == "PROPERTY"):
umi_prop = current.get_property()
col.prop(umi_prop, "id_name")
col.prop(umi_prop, "context")
else:
col.label(text="No item selected.")
def draw_user_menu_preference_expanded(context, layout, kmi, map_type):
prefs = context.preferences
um = prefs.user_menus
box = layout.box()
sub = box.row()
if kmi:
if map_type not in {'TEXTINPUT', 'TIMER'}:
sub = box.column()
subrow = sub.row(align=True)
if map_type == 'KEYBOARD':
subrow.prop(kmi, "type", text="", event=True)
subrow.prop(kmi, "value", text="")
subrow_repeat = subrow.row(align=True)
subrow_repeat.active = kmi.value in {'ANY', 'PRESS'}
subrow_repeat.prop(kmi, "repeat", text="Repeat")
elif map_type in {'MOUSE', 'NDOF'}:
subrow.prop(kmi, "type", text="")
subrow.prop(kmi, "value", text="")
subrow = sub.row()
subrow.scale_x = 0.75
subrow.prop(kmi, "any", toggle=True)
subrow.prop(kmi, "shift", toggle=True)
subrow.prop(kmi, "ctrl", toggle=True)
subrow.prop(kmi, "alt", toggle=True)
subrow.prop(kmi, "oskey", text="Cmd", toggle=True)
subrow.prop(kmi, "key_modifier", text="", event=True)
else:
sub.label(text="No key set")
def draw_user_menu_preference(context, layout):
prefs = context.preferences
um = prefs.user_menus
umg = um.active_group
kmi = get_keymap(context, None, False)
map_type = None
box = layout.box()
row = box.row()
row.prop(um, "expanded", text="", emboss=False)
qf = um.menus[0]
if umg != qf:
row.prop(umg, "name")
pie_text = "List"
if umg.type == "PIE":
pie_text = "Pie"
row.prop(umg, "type", text=pie_text, expand=True)
if kmi:
row.prop(kmi, "map_type", text="")
map_type = kmi.map_type
if map_type == 'KEYBOARD':
row.prop(kmi, "type", text="", full_event=True)
elif map_type == 'MOUSE':
row.prop(kmi, "type", text="", full_event=True)
elif map_type == 'NDOF':
row.prop(kmi, "type", text="", full_event=True)
elif map_type == 'TWEAK':
subrow = row.row()
subrow.prop(kmi, "type", text="")
subrow.prop(kmi, "value", text="")
elif map_type == 'TIMER':
row.prop(kmi, "type", text="")
else:
row.label()
if um.expanded:
draw_user_menu_preference_expanded(context=context, layout=box, kmi=kmi, map_type=map_type)
def menu_id(context, umg):
prefs = context.preferences
um = prefs.user_menus
i = 0
for item in um.menus:
if item == umg:
return i
i = i + 1
return -1
def draw_user_menus(context, layout):
prefs = context.preferences
um = prefs.user_menus
if not um.active_group:
um.active_group = um.menus[0]
split = layout.split(factor=0.4)
row = split.row()
rowsub = row.row(align=True)
rowsub.menu("USERPREF_MT_menu_select", text=um.active_group.name)
rowsub.operator("preferences.usermenus_add", text="", icon='ADD')
rowsub.operator("preferences.usermenus_remove", text="", icon='REMOVE')
rowsub = split.row(align=True)
rowsub.prop(um, "space_selected", text="")
rowsub = split.row(align=True)
rowsub.prop(um, "context_selected", text="")
#rowsub = split.row(align=True)
#rowsub.operator("preferences.keyconfig_import", text="", icon='IMPORT')
#rowsub.operator("preferences.keyconfig_export", text="", icon='EXPORT')
row = layout.row()
row.separator()
draw_user_menu_preference(context=context, layout=row)
row = layout.row()
row.separator()
if um.active_group.type == "PIE":
draw_pie(context=context, row=row)
else:
draw_item_box(context=context, row=row)
draw_item_editor(context=context, row=row)
row.separator()

View File

@@ -157,6 +157,8 @@ def op_menu(menu, kmi_args):
def op_menu_pie(menu, kmi_args):
return ("wm.call_menu_pie", kmi_args, {"properties": [("name", menu)]})
def op_user_menu(menu, kmi_args):
return ("wm.call_user_menu", kmi_args, {"properties": [("name", menu)]})
def op_panel(menu, kmi_args, kmi_data=()):
return ("wm.call_panel", kmi_args, {"properties": [("name", menu), *kmi_data]})
@@ -407,7 +409,7 @@ def km_window(params):
("wm.quit_blender", {"type": 'Q', "value": 'PRESS', "ctrl": True}, None),
# Quick menu and toolbar
op_menu("SCREEN_MT_user_menu", {"type": 'Q', "value": 'PRESS'}),
op_user_menu("QUICK_FAVORITES", {"type": 'Q', "value": 'PRESS'}),
# Fast editor switching
*(

View File

@@ -67,6 +67,8 @@ def op_menu(menu, kmi_args):
def op_menu_pie(menu, kmi_args):
return ("wm.call_menu_pie", kmi_args, {"properties": [("name", menu)]})
def op_user_menu(menu, kmi_args):
return ("wm.call_user_menu", kmi_args, {"properties": [("name", menu)]})
def op_panel(menu, kmi_args, kmi_data=()):
return ("wm.call_panel", kmi_args, {"properties": [("name", menu), *kmi_data]})
@@ -210,7 +212,7 @@ def km_window(params):
("wm.quit_blender", {"type": 'Q', "value": 'PRESS', "ctrl": True}, None),
# Quick menu and toolbar
op_menu("SCREEN_MT_user_menu", {"type": 'TAB', "value": 'PRESS', "shift": True}),
op_user_menu("QUICK_FAVORITES", {"type": 'Q', "value": 'PRESS'}),
# NDOF settings
op_panel("USERPREF_PT_ndof_settings", {"type": 'NDOF_BUTTON_MENU', "value": 'PRESS'}),

View File

@@ -602,7 +602,6 @@ class AddPresetOperator(AddPresetBase, Operator):
prefix, suffix = operator.split("_OT_", 1)
return os.path.join("operator", "%s.%s" % (prefix.lower(), suffix))
class WM_MT_operator_presets(Menu):
bl_label = "Operator Presets"

View File

@@ -51,6 +51,8 @@ def module_filesystem_remove(path_base, module_name):
# This duplicates shutil.copytree from Python 3.8, with the new dirs_exist_ok
# argument that we need. Once we upgrade to 3.8 we can remove this.
def _preferences_copytree(entries, src, dst):
import os
import shutil
@@ -85,11 +87,13 @@ def _preferences_copytree(entries, src, dst):
raise Error(errors)
return dst
def preferences_copytree(src, dst):
import os
with os.scandir(src) as entries:
return _preferences_copytree(entries=entries, src=src, dst=dst)
class PREFERENCES_OT_keyconfig_activate(Operator):
bl_idname = "preferences.keyconfig_activate"
bl_label = "Activate Keyconfig"
@@ -241,7 +245,8 @@ class PREFERENCES_OT_keyconfig_import(Operator):
config_name = basename(self.filepath)
path = bpy.utils.user_resource('SCRIPTS', os.path.join("presets", "keyconfig"), create=True)
path = bpy.utils.user_resource(
'SCRIPTS', os.path.join("presets", "keyconfig"), create=True)
path = os.path.join(path, config_name)
try:
@@ -460,7 +465,8 @@ class PREFERENCES_OT_addon_enable(Operator):
err_str = traceback.format_exc()
print(err_str)
mod = addon_utils.enable(self.module, default_set=True, handle_error=err_cb)
mod = addon_utils.enable(
self.module, default_set=True, handle_error=err_cb)
if mod:
info = addon_utils.module_bl_info(mod)
@@ -544,7 +550,8 @@ class PREFERENCES_OT_theme_install(Operator):
xmlfile = self.filepath
path_themes = bpy.utils.user_resource('SCRIPTS', "presets/interface_theme", create=True)
path_themes = bpy.utils.user_resource(
'SCRIPTS', "presets/interface_theme", create=True)
if not path_themes:
self.report({'ERROR'}, "Failed to get themes path")
@@ -554,7 +561,8 @@ class PREFERENCES_OT_theme_install(Operator):
if not self.overwrite:
if os.path.exists(path_dest):
self.report({'WARNING'}, "File already installed to %r\n" % path_dest)
self.report(
{'WARNING'}, "File already installed to %r\n" % path_dest)
return {'CANCELLED'}
try:
@@ -638,7 +646,8 @@ class PREFERENCES_OT_addon_install(Operator):
if self.target == 'DEFAULT':
# don't use bpy.utils.script_paths("addons") because we may not be able to write to it.
path_addons = bpy.utils.user_resource('SCRIPTS', "addons", create=True)
path_addons = bpy.utils.user_resource(
'SCRIPTS', "addons", create=True)
else:
path_addons = context.preferences.filepaths.script_directory
if path_addons:
@@ -661,7 +670,8 @@ class PREFERENCES_OT_addon_install(Operator):
pyfile_dir = os.path.dirname(pyfile)
for addon_path in addon_utils.paths():
if os.path.samefile(pyfile_dir, addon_path):
self.report({'ERROR'}, "Source file is in the add-on search path: %r" % addon_path)
self.report(
{'ERROR'}, "Source file is in the add-on search path: %r" % addon_path)
return {'CANCELLED'}
del addon_path
del pyfile_dir
@@ -684,7 +694,8 @@ class PREFERENCES_OT_addon_install(Operator):
for f in file_to_extract.namelist():
path_dest = os.path.join(path_addons, os.path.basename(f))
if os.path.exists(path_dest):
self.report({'WARNING'}, "File already installed to %r\n" % path_dest)
self.report(
{'WARNING'}, "File already installed to %r\n" % path_dest)
return {'CANCELLED'}
try: # extract the file to "addons"
@@ -699,7 +710,8 @@ class PREFERENCES_OT_addon_install(Operator):
if self.overwrite:
module_filesystem_remove(path_addons, os.path.basename(pyfile))
elif os.path.exists(path_dest):
self.report({'WARNING'}, "File already installed to %r\n" % path_dest)
self.report(
{'WARNING'}, "File already installed to %r\n" % path_dest)
return {'CANCELLED'}
# if not compressed file just copy into the addon path
@@ -709,7 +721,8 @@ class PREFERENCES_OT_addon_install(Operator):
traceback.print_exc()
return {'CANCELLED'}
addons_new = {mod.__name__ for mod in addon_utils.modules()} - addons_old
addons_new = {mod.__name__ for mod in addon_utils.modules()} - \
addons_old
addons_new.discard("modules")
# disable any addons we may have enabled previously and removed.
@@ -779,7 +792,8 @@ class PREFERENCES_OT_addon_remove(Operator):
path, isdir = PREFERENCES_OT_addon_remove.path_from_addon(self.module)
if path is None:
self.report({'WARNING'}, "Add-on path %r could not be found" % path)
self.report(
{'WARNING'}, "Add-on path %r could not be found" % path)
return {'CANCELLED'}
# in case its enabled
@@ -925,9 +939,11 @@ class PREFERENCES_OT_app_template_install(Operator):
module_filesystem_remove(path_app_templates, f)
else:
for f in file_to_extract.namelist():
path_dest = os.path.join(path_app_templates, os.path.basename(f))
path_dest = os.path.join(
path_app_templates, os.path.basename(f))
if os.path.exists(path_dest):
self.report({'WARNING'}, "File already installed to %r\n" % path_dest)
self.report(
{'WARNING'}, "File already installed to %r\n" % path_dest)
return {'CANCELLED'}
try: # extract the file to "bl_app_templates_user"
@@ -941,7 +957,8 @@ class PREFERENCES_OT_app_template_install(Operator):
self.report({'WARNING'}, "Expected a zip-file %r\n" % filepath)
return {'CANCELLED'}
app_templates_new = set(os.listdir(path_app_templates)) - app_templates_old
app_templates_new = set(os.listdir(
path_app_templates)) - app_templates_old
# in case a new module path was created to install this addon.
bpy.utils.refresh_script_paths()
@@ -1001,14 +1018,17 @@ class PREFERENCES_OT_studiolight_install(Operator):
prefs = context.preferences
path_studiolights = os.path.join("studiolights", self.type.lower())
path_studiolights = bpy.utils.user_resource('DATAFILES', path_studiolights, create=True)
path_studiolights = bpy.utils.user_resource(
'DATAFILES', path_studiolights, create=True)
if not path_studiolights:
self.report({'ERROR'}, "Failed to create Studio Light path")
return {'CANCELLED'}
for e in self.files:
shutil.copy(os.path.join(self.directory, e.name), path_studiolights)
prefs.studio_lights.load(os.path.join(path_studiolights, e.name), self.type)
shutil.copy(os.path.join(self.directory, e.name),
path_studiolights)
prefs.studio_lights.load(os.path.join(
path_studiolights, e.name), self.type)
# print message
msg = (
@@ -1047,7 +1067,8 @@ class PREFERENCES_OT_studiolight_new(Operator):
wm = context.window_manager
filename = bpy.path.ensure_ext(self.filename, ".sl")
path_studiolights = bpy.utils.user_resource('DATAFILES', os.path.join("studiolights", "studio"), create=True)
path_studiolights = bpy.utils.user_resource(
'DATAFILES', os.path.join("studiolights", "studio"), create=True)
if not path_studiolights:
self.report({'ERROR'}, "Failed to get Studio Light path")
return {'CANCELLED'}
@@ -1060,7 +1081,8 @@ class PREFERENCES_OT_studiolight_new(Operator):
else:
for studio_light in prefs.studio_lights:
if studio_light.name == filename:
bpy.ops.preferences.studiolight_uninstall(index=studio_light.index)
bpy.ops.preferences.studiolight_uninstall(
index=studio_light.index)
prefs.studio_lights.new(path=filepath_final)
@@ -1076,7 +1098,8 @@ class PREFERENCES_OT_studiolight_new(Operator):
def draw(self, _context):
layout = self.layout
if self.ask_overide:
layout.label(text="Warning, file already exists. Overwrite existing file?")
layout.label(
text="Warning, file already exists. Overwrite existing file?")
else:
layout.prop(self, "filename")
@@ -1141,6 +1164,184 @@ class PREFERENCES_OT_studiolight_show(Operator):
bpy.ops.screen.userpref_show('INVOKE_DEFAULT')
return {'FINISHED'}
# -----------------------------------------------------------------------------
# User Menus Operators
class PREFERENCES_OT_usermenus_select(Operator):
bl_idname = "preferences.usermenus_select"
bl_label = "select user menu to edit"
index: IntProperty()
def execute(self, _context):
prefs = _context.preferences
um = prefs.user_menus
i = 0
for umg in um.menus:
if i == self.index:
um.set_group(new_group=umg)
return {'FINISHED'}
i = i + 1
return {'CANCELLED'}
class PREFERENCES_OT_usermenus_add(Operator):
bl_idname = "preferences.usermenus_add"
bl_label = "add an user menus group"
def execute(self, _context):
prefs = _context.preferences
um = prefs.user_menus
um.add_group()
return {'FINISHED'}
class PREFERENCES_OT_usermenus_remove(Operator):
bl_idname = "preferences.usermenus_remove"
bl_label = "remove an user menus group"
@classmethod
def poll(self, context):
prefs = context.preferences
um = prefs.user_menus
if um.active_group.idname == "QUICK_FAVORITES":
return False
return True
def execute(self, _context):
prefs = _context.preferences
um = prefs.user_menus
um.remove_group()
return {'FINISHED'}
class PREFERENCES_OT_menuitem_add(Operator):
"""Add user menu item"""
bl_idname = "preferences.menuitem_add"
bl_label = "Add User Menu Item"
index: IntProperty()
def execute(self, context):
prefs = context.preferences
um = prefs.user_menus
um.item_add(index=self.index)
context.preferences.is_dirty = True
return {'FINISHED'}
class PREFERENCES_OT_menuitem_remove(Operator):
"""Remove user menu item"""
bl_idname = "preferences.menuitem_remove"
bl_label = "Remove User Menu Item"
@classmethod
def poll(self, context):
prefs = context.preferences
um = prefs.user_menus
can_remove = um.active_item
um_type = um.active_group.type
if um_type == "PIE" and can_remove:
if not can_remove.parent:
return False
return can_remove
def execute(self, context):
prefs = context.preferences
um = prefs.user_menus
um.item_remove()
context.preferences.is_dirty = True
return {'FINISHED'}
class PREFERENCES_OT_menuitem_up(Operator):
"""move up an user menu item"""
bl_idname = "preferences.menuitem_up"
bl_label = "Move Up An User Menu Item"
@classmethod
def poll(self, context):
prefs = context.preferences
um = prefs.user_menus
current = um.active_item
um_type = um.active_group.type
if not current:
return False
if um_type == "PIE":
if not current.parent:
return False
prev_item = current.prev
if prev_item:
return True
if current.parent.item.parent:
return True
return False
else:
prev_item = current.prev
if prev_item or current.parent:
return True
return False
def execute(self, context):
prefs = context.preferences
um = prefs.user_menus
um.item_move(up=True)
context.preferences.is_dirty = True
return {'FINISHED'}
class PREFERENCES_OT_menuitem_down(Operator):
"""move up an user menu item"""
bl_idname = "preferences.menuitem_down"
bl_label = "Move Up An User Menu Item"
@classmethod
def poll(self, context):
prefs = context.preferences
um = prefs.user_menus
um_type = um.active_group.type
current = um.active_item
if not current:
return False
if um_type == "PIE":
if not current.parent:
return False
next_item = current.next
if next_item:
return True
if current.parent.item.parent:
return True
return False
else:
next_item = current.next
if next_item or current.parent:
return True
return False
def execute(self, context):
prefs = context.preferences
um = prefs.user_menus
um.item_move(up=False)
context.preferences.is_dirty = True
return {'FINISHED'}
class PREFERENCES_OT_pie_menuitem_add(Operator):
"""Add user menu item"""
bl_idname = "preferences.pie_menuitem_add"
bl_label = "Add User Menu Item"
index: IntProperty()
def execute(self, context):
prefs = context.preferences
um = prefs.user_menus
um.pie_item_add(index=self.index)
context.preferences.is_dirty = True
return {'FINISHED'}
classes = (
PREFERENCES_OT_addon_disable,
@@ -1167,4 +1368,12 @@ classes = (
PREFERENCES_OT_studiolight_uninstall,
PREFERENCES_OT_studiolight_copy_settings,
PREFERENCES_OT_studiolight_show,
PREFERENCES_OT_usermenus_select,
PREFERENCES_OT_usermenus_add,
PREFERENCES_OT_usermenus_remove,
PREFERENCES_OT_menuitem_add,
PREFERENCES_OT_menuitem_remove,
PREFERENCES_OT_menuitem_up,
PREFERENCES_OT_menuitem_down,
PREFERENCES_OT_pie_menuitem_add,
)

View File

@@ -2633,6 +2633,36 @@ class WM_OT_drop_blend_file(Operator):
col.operator("wm.link", text="Link...", icon='LINK_BLEND').filepath = self.filepath
col.operator("wm.append", text="Append...", icon='APPEND_BLEND').filepath = self.filepath
class WM_OT_call_user_menu(Operator):
bl_idname = "wm.call_user_menu"
bl_label = "display user menu"
name: StringProperty()
def execute(self, context):
return {'FINISHED'}
def draw_menu(self, menu, context):
prefs = context.preferences
um = prefs.user_menus
umg = um.get_group(idname=self.name)
layout = menu.layout
if umg.type == "PIE":
layout = layout.menu_pie()
um.draw_menu(context=context, layout=layout, menu=umg)
def invoke(self, context, event):
prefs = context.preferences
um = prefs.user_menus
wm = context.window_manager
umg = um.get_group(idname=self.name)
if umg.type == "PIE":
wm.popup_menu_pie(draw_func=self.draw_menu, title=umg.name, event=event)
else:
wm.popup_menu(self.draw_menu, title=umg.name)
return {'FINISHED'}
classes = (
WM_OT_context_collection_boolean_set,
@@ -2677,4 +2707,5 @@ classes = (
WM_OT_batch_rename,
WM_MT_splash,
WM_MT_splash_about,
WM_OT_call_user_menu,
)

View File

@@ -1684,8 +1684,37 @@ class USERPREF_PT_keymap(KeymapPanel, Panel):
# Keymap Settings
draw_keymaps(context, layout)
# print("runtime", time.time() - start)
# -----------------------------------------------------------------------------
# Custom Menu Editor Panels
class UserMenusPanel:
bl_space_type = 'PREFERENCES'
bl_region_type = 'WINDOW'
bl_context = "user_menus"
class USERPREF_MT_menu_select(Menu):
bl_label = "Menus group select"
def draw(self, context):
prefs = context.preferences
um = prefs.user_menus
layout = self.layout
index = 0
for umg in um.menus:
layout.operator("preferences.usermenus_select", text=umg.name).index = index
index = index + 1
class USERPREF_PT_user_menus(UserMenusPanel, Panel):
bl_label = "user_menus"
bl_options = {'HIDE_HEADER'}
def draw(self, context):
from rna_user_menus_ui import draw_user_menus
layout = self.layout
draw_user_menus(context, layout)
# -----------------------------------------------------------------------------
# Add-On Panels
@@ -2278,6 +2307,8 @@ classes = (
USERPREF_PT_navigation_fly_walk_gravity,
USERPREF_PT_keymap,
USERPREF_MT_menu_select,
USERPREF_PT_user_menus,
USERPREF_PT_addons,
USERPREF_PT_studiolight_lights,

View File

@@ -27,7 +27,16 @@ extern "C" {
struct ListBase;
struct bUserMenu;
struct bUserMenuItem;
struct wmWindowManager;
struct bUserMenusGroup;
void BKE_blender_user_menu_free_list(struct ListBase *lb);
void BKE_blender_user_menus_group_idname_update(struct bUserMenusGroup *umg);
void BKE_blender_user_menus_group_idname_update_keymap(struct wmWindowManager *wm,
const char *old,
const char *new);
struct bUserMenusGroup *BKE_blender_user_menus_group_new(const char *name);
struct bUserMenusGroup *BKE_blender_user_menus_group_find(struct ListBase *lb, const char *idname);
struct bUserMenu *BKE_blender_user_menu_find(struct ListBase *lb,
char space_type,
const char *context);
@@ -38,6 +47,7 @@ struct bUserMenu *BKE_blender_user_menu_ensure(struct ListBase *lb,
struct bUserMenuItem *BKE_blender_user_menu_item_add(struct ListBase *lb, int type);
void BKE_blender_user_menu_item_free(struct bUserMenuItem *umi);
void BKE_blender_user_menu_item_free_list(struct ListBase *lb);
struct bUserMenusGroup *BKU_blender_user_menu_default(void);
#ifdef __cplusplus
}

View File

@@ -255,6 +255,7 @@ struct ViewLayer *CTX_data_view_layer(const bContext *C);
struct RenderEngineType *CTX_data_engine_type(const bContext *C);
struct ToolSettings *CTX_data_tool_settings(const bContext *C);
const char **CTX_data_list_mode_string(void);
const char *CTX_data_mode_string(const bContext *C);
enum eContextObjectMode CTX_data_mode_enum_ex(const struct Object *obedit,
const struct Object *ob,

View File

@@ -238,10 +238,14 @@ static void userdef_free_keyconfig_prefs(UserDef *userdef)
static void userdef_free_user_menus(UserDef *userdef)
{
for (bUserMenu *um = userdef->user_menus.first, *um_next; um; um = um_next) {
um_next = um->next;
BKE_blender_user_menu_item_free_list(&um->items);
MEM_freeN(um);
for (bUserMenusGroup *umg = userdef->user_menus_group.first, *umg_next; umg; umg = umg_next) {
umg_next = umg->next;
for (bUserMenu *um = umg->menus.first, *um_next; um; um = um_next) {
um_next = um->next;
BKE_blender_user_menu_item_free_list(&um->items);
MEM_freeN(um);
}
MEM_freeN(umg);
}
}

View File

@@ -26,12 +26,97 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_utils.h"
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
#include "RNA_access.h"
#include "BKE_blender_user_menu.h"
#include "BKE_idprop.h"
/* -------------------------------------------------------------------- */
/** \name Menu group
* \{ */
void BKE_blender_user_menu_free_list(ListBase *lb)
{
for (bUserMenu *um = lb->first, *um_next; um; um = um_next) {
um_next = um->next;
BKE_blender_user_menu_item_free_list(&um->items);
MEM_freeN(um);
}
BLI_listbase_clear(lb);
}
bUserMenusGroup *BKE_blender_user_menus_group_find(ListBase *lb, const char *idname)
{
LISTBASE_FOREACH (bUserMenusGroup *, umg, lb) {
if ((STREQ(idname, umg->idname))) {
return umg;
}
}
return NULL;
}
void BKE_blender_user_menus_group_idname_update(bUserMenusGroup *umg)
{
char name[64];
STRNCPY(name, umg->name);
for (int i = 0; name[i]; i++) {
if (name[i] == ' ')
name[i] = '_';
if (name[i] >= 'a' && name[i] <= 'z')
name[i] += 'A' - 'a';
}
STRNCPY(umg->idname, name);
BLI_uniquename(&U.user_menus_group,
umg,
umg->idname,
'_',
offsetof(bUserMenusGroup, idname),
sizeof(umg->idname));
}
void BKE_blender_user_menus_group_idname_update_keymap(wmWindowManager *wm,
const char *old,
const char *new)
{
wmKeyConfig *kc;
wmKeyMap *km;
for (kc = wm->keyconfigs.first; kc; kc = kc->next) {
for (km = kc->keymaps.first; km; km = km->next) {
wmKeyMapItem *kmi;
for (kmi = km->items.first; kmi; kmi = kmi->next) {
if (STREQ(kmi->idname, "WM_OT_call_user_menu")) {
IDProperty *idp = IDP_GetPropertyFromGroup(kmi->properties, "name");
char *index = IDP_String(idp);
if (STREQ(index, old)) {
IDP_AssignString(idp, new, 64);
}
}
}
}
}
}
bUserMenusGroup *BKE_blender_user_menus_group_new(const char *name)
{
bUserMenusGroup *umg = MEM_mallocN(sizeof(*umg), __func__);
STRNCPY(umg->name, name);
umg->type = 0;
umg->prev = NULL;
umg->next = NULL;
BLI_listbase_clear(&umg->menus);
BKE_blender_user_menus_group_idname_update(umg);
return umg;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Menu Type
* \{ */
@@ -50,8 +135,10 @@ bUserMenu *BKE_blender_user_menu_ensure(ListBase *lb, char space_type, const cha
{
bUserMenu *um = BKE_blender_user_menu_find(lb, space_type, context);
if (um == NULL) {
um = MEM_callocN(sizeof(bUserMenu), __func__);
um->space_type = space_type;
BLI_listbase_clear(&um->items);
STRNCPY(um->context, context);
BLI_addhead(lb, um);
}
@@ -80,6 +167,9 @@ bUserMenuItem *BKE_blender_user_menu_item_add(ListBase *lb, int type)
else if (type == USER_MENU_TYPE_PROP) {
size = sizeof(bUserMenuItem_Prop);
}
else if (type == USER_MENU_TYPE_SUBMENU) {
size = sizeof(bUserMenuItem_SubMenu);
}
else {
size = sizeof(bUserMenuItem);
BLI_assert(0);
@@ -87,7 +177,9 @@ bUserMenuItem *BKE_blender_user_menu_item_add(ListBase *lb, int type)
bUserMenuItem *umi = MEM_callocN(size, __func__);
umi->type = type;
BLI_addtail(lb, umi);
umi->icon = 0;
if (lb)
BLI_addtail(lb, umi);
return umi;
}
@@ -99,6 +191,10 @@ void BKE_blender_user_menu_item_free(bUserMenuItem *umi)
IDP_FreeProperty(umi_op->prop);
}
}
if (umi->type == USER_MENU_TYPE_SUBMENU) {
bUserMenuItem_SubMenu *umi_sm = (bUserMenuItem_SubMenu *)umi;
BKE_blender_user_menu_item_free_list(&umi_sm->items);
}
MEM_freeN(umi);
}
@@ -110,3 +206,19 @@ void BKE_blender_user_menu_item_free_list(ListBase *lb)
}
BLI_listbase_clear(lb);
}
/* -------------------------------------------------------------------- */
/** \name Default Menu
* \{ */
bUserMenusGroup *BKU_blender_user_menu_default(void)
{
bUserMenusGroup *umg = MEM_mallocN(sizeof(*umg), __func__);
STRNCPY(umg->name, "Quick Favorites");
STRNCPY(umg->idname, "QUICK_FAVORITES");
umg->type = 0;
umg->prev = NULL;
umg->next = NULL;
BLI_listbase_clear(&umg->menus);
return umg;
}

View File

@@ -57,6 +57,7 @@
#include "BKE_screen.h"
#include "BKE_studiolight.h"
#include "BKE_workspace.h"
#include "BKE_blender_user_menu.h"
#include "BLO_readfile.h"
#include "BLO_writefile.h"
@@ -614,6 +615,13 @@ UserDef *BKE_blendfile_userdef_from_defaults(void)
BLI_addtail(&userdef->themes, btheme);
}
/* default user menus. */
{
bUserMenusGroup *umg = BKU_blender_user_menu_default();
BLI_addtail(&userdef->user_menus_group, umg);
userdef->runtime.umg_select = umg;
}
#ifdef WITH_PYTHON_SECURITY
/* use alternative setting for security nuts
* otherwise we'd need to patch the binary blob - startup.blend.c */

View File

@@ -1151,6 +1151,11 @@ const char *CTX_data_mode_string(const bContext *C)
return data_mode_strings[CTX_data_mode_enum(C)];
}
const char **CTX_data_list_mode_string(void)
{
return data_mode_strings;
}
void CTX_data_scene_set(bContext *C, Scene *scene)
{
C->data.scene = scene;

View File

@@ -114,6 +114,7 @@
#include "BKE_action.h"
#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_blender_user_menu.h"
#include "BKE_brush.h"
#include "BKE_collection.h"
#include "BKE_colortools.h"
@@ -159,6 +160,8 @@
#include "BKE_volume.h"
#include "BKE_workspace.h"
#include "BKE_blender_user_menu.h"
#include "DRW_engine.h"
#include "DEG_depsgraph.h"
@@ -8897,6 +8900,26 @@ static void direct_link_keymapitem(BlendDataReader *reader, wmKeyMapItem *kmi)
kmi->flag &= ~KMI_UPDATE;
}
static void read_usermenuitems(BlendDataReader *reader,
ListBase *lb,
bUserMenuItem_SubMenu *parent)
{
LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
umi->parent = parent;
if (umi->type == USER_MENU_TYPE_OPERATOR) {
bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
BLO_read_data_address(reader, &umi_op->prop);
IDP_BlendDataRead(reader, &umi_op->prop);
}
if (umi->type == USER_MENU_TYPE_SUBMENU) {
bUserMenuItem_SubMenu *umi_sm = (bUserMenuItem_SubMenu *)umi;
BLI_listbase_clear(&umi_sm->items);
BLO_read_list(reader, &umi_sm->items);
read_usermenuitems(reader, &umi_sm->items, umi_sm);
}
}
}
static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
{
UserDef *user;
@@ -8918,6 +8941,7 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
BLO_read_list(reader, &user->user_menus);
BLO_read_list(reader, &user->addons);
BLO_read_list(reader, &user->autoexec_paths);
BLO_read_list(reader, &user->user_menus_group);
LISTBASE_FOREACH (wmKeyMap *, keymap, &user->user_keymaps) {
keymap->modal_items = NULL;
@@ -8951,13 +8975,7 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
LISTBASE_FOREACH (bUserMenu *, um, &user->user_menus) {
BLO_read_list(reader, &um->items);
LISTBASE_FOREACH (bUserMenuItem *, umi, &um->items) {
if (umi->type == USER_MENU_TYPE_OPERATOR) {
bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
BLO_read_data_address(reader, &umi_op->prop);
IDP_BlendDataRead(reader, &umi_op->prop);
}
}
read_usermenuitems(reader, &um->items, NULL);
}
LISTBASE_FOREACH (bAddon *, addon, &user->addons) {
@@ -8965,6 +8983,23 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
IDP_BlendDataRead(reader, &addon->prop);
}
LISTBASE_FOREACH (bUserMenusGroup *, umg, &user->user_menus_group) {
BLO_read_list(reader, &umg->menus);
BKE_blender_user_menus_group_idname_update(umg);
LISTBASE_FOREACH (bUserMenu *, um, &umg->menus) {
BLO_read_list(reader, &um->items);
read_usermenuitems(reader, &um->items, NULL);
}
}
if (user->user_menus.first != NULL && user->user_menus_group.first == NULL) {
bUserMenusGroup *umg = BKU_blender_user_menu_default();
BLI_addtail(&user->user_menus_group, umg);
user->runtime.umg_select = umg;
umg->menus = user->user_menus;
BLI_listbase_clear(&user->user_menus);
}
// XXX
user->uifonts.first = user->uifonts.last = NULL;
@@ -8976,6 +9011,10 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
/* Clear runtime data. */
user->runtime.is_dirty = false;
user->edit_studio_light = 0;
user->runtime.um_space_select = 1;
user->runtime.um_context_select = 1;
user->runtime.um_item_select = NULL;
user->runtime.umg_select = user->user_menus_group.first;
/* free fd->datamap again */
oldnewmap_clear(fd->datamap);

View File

@@ -980,7 +980,37 @@ static void write_keymapitem(BlendWriter *writer, const wmKeyMapItem *kmi)
}
}
static void write_usermenuitems(BlendWriter *writer, const ListBase *lb)
{
LISTBASE_FOREACH (const bUserMenuItem *, umi, lb) {
if (umi->type == USER_MENU_TYPE_OPERATOR) {
const bUserMenuItem_Op *umi_op = (const bUserMenuItem_Op *)umi;
BLO_write_struct(writer, bUserMenuItem_Op, umi_op);
if (umi_op->prop) {
IDP_BlendWrite(writer, umi_op->prop);
}
}
else if (umi->type == USER_MENU_TYPE_MENU) {
const bUserMenuItem_Menu *umi_mt = (const bUserMenuItem_Menu *)umi;
BLO_write_struct(writer, bUserMenuItem_Menu, umi_mt);
}
else if (umi->type == USER_MENU_TYPE_PROP) {
const bUserMenuItem_Prop *umi_pr = (const bUserMenuItem_Prop *)umi;
BLO_write_struct(writer, bUserMenuItem_Prop, umi_pr);
}
else if (umi->type == USER_MENU_TYPE_SUBMENU) {
const bUserMenuItem_SubMenu *umi_sm = (const bUserMenuItem_SubMenu *)umi;
BLO_write_struct(writer, bUserMenuItem_SubMenu, umi_sm);
write_usermenuitems(writer, &umi_sm->items);
}
else {
BLO_write_struct(writer, bUserMenuItem, umi);
}
}
}
static void write_userdef(BlendWriter *writer, const UserDef *userdef)
{
writestruct(writer->wd, USER, UserDef, 1, userdef);
@@ -1013,30 +1043,6 @@ static void write_userdef(BlendWriter *writer, const UserDef *userdef)
}
}
LISTBASE_FOREACH (const bUserMenu *, um, &userdef->user_menus) {
BLO_write_struct(writer, bUserMenu, um);
LISTBASE_FOREACH (const bUserMenuItem *, umi, &um->items) {
if (umi->type == USER_MENU_TYPE_OPERATOR) {
const bUserMenuItem_Op *umi_op = (const bUserMenuItem_Op *)umi;
BLO_write_struct(writer, bUserMenuItem_Op, umi_op);
if (umi_op->prop) {
IDP_BlendWrite(writer, umi_op->prop);
}
}
else if (umi->type == USER_MENU_TYPE_MENU) {
const bUserMenuItem_Menu *umi_mt = (const bUserMenuItem_Menu *)umi;
BLO_write_struct(writer, bUserMenuItem_Menu, umi_mt);
}
else if (umi->type == USER_MENU_TYPE_PROP) {
const bUserMenuItem_Prop *umi_pr = (const bUserMenuItem_Prop *)umi;
BLO_write_struct(writer, bUserMenuItem_Prop, umi_pr);
}
else {
BLO_write_struct(writer, bUserMenuItem, umi);
}
}
}
LISTBASE_FOREACH (const bAddon *, bext, &userdef->addons) {
BLO_write_struct(writer, bAddon, bext);
if (bext->prop) {
@@ -1048,6 +1054,14 @@ static void write_userdef(BlendWriter *writer, const UserDef *userdef)
BLO_write_struct(writer, bPathCompare, path_cmp);
}
LISTBASE_FOREACH (const bUserMenusGroup *, umg, &userdef->user_menus_group) {
BLO_write_struct(writer, bUserMenusGroup, umg);
LISTBASE_FOREACH (const bUserMenu *, um, &umg->menus) {
BLO_write_struct(writer, bUserMenu, um);
write_usermenuitems(writer, &um->items);
}
}
LISTBASE_FOREACH (const uiStyle *, style, &userdef->uistyles) {
BLO_write_struct(writer, uiStyle, style);
}

View File

@@ -374,8 +374,12 @@ bool ED_operator_camera(struct bContext *C);
/* screen_user_menu.c */
bUserMenu **ED_screen_user_menus_find(const struct bContext *C, uint *r_len);
struct bUserMenu *ED_screen_user_menu_ensure(struct bContext *C);
struct bUserMenusGroup *ED_screen_user_menus_group_find(int id);
struct bUserMenu **ED_screen_user_menus_find_menu(const struct bContext *C,
uint *r_len,
struct bUserMenusGroup *umg);
struct bUserMenu **ED_screen_user_menus_find(const struct bContext *C, uint *r_len, int id);
struct bUserMenu *ED_screen_user_menu_ensure(struct bContext *C, int id);
struct bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(struct ListBase *lb,
const struct wmOperatorType *ot,
@@ -396,7 +400,8 @@ void ED_screen_user_menu_item_add_operator(struct ListBase *lb,
void ED_screen_user_menu_item_add_menu(struct ListBase *lb,
const char *ui_name,
const struct MenuType *mt);
void ED_screen_user_menu_item_add_prop(ListBase *lb,
void ED_screen_user_menu_item_add_prop(struct bContext *C,
ListBase *lb,
const char *ui_name,
const char *context_data_path,
const char *prop_id,
@@ -404,6 +409,14 @@ void ED_screen_user_menu_item_add_prop(ListBase *lb,
void ED_screen_user_menu_item_remove(struct ListBase *lb, struct bUserMenuItem *umi);
void ED_screen_user_menu_register(void);
bool screen_user_menu_draw_items(const struct bContext *C,
struct uiLayout *layout,
struct ListBase *lb,
char type);
void screen_user_menu_draw_begin(struct bContext *C,
struct uiLayout *layout,
char type,
struct bUserMenusGroup *umg);
/* Cache display helpers */

View File

@@ -2113,6 +2113,7 @@ void uiTemplateCacheFile(uiLayout *layout,
const struct bContext *C,
struct PointerRNA *ptr,
const char *propname);
void uiTemplateUserMenuItemProperties(uiLayout *layout, PointerRNA *ptr);
/* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"

View File

@@ -437,7 +437,8 @@ static void ui_but_user_menu_add(bContext *C, uiBut *but, bUserMenu *um)
}
const char *prop_id = RNA_property_identifier(but->rnaprop);
/* Note, ignore 'drawstr', use property idname always. */
ED_screen_user_menu_item_add_prop(&um->items, "", member_id_data_path, prop_id, but->rnaindex);
ED_screen_user_menu_item_add_prop(
C, &um->items, "", member_id_data_path, prop_id, but->rnaindex);
if (data_path) {
MEM_freeN((void *)data_path);
}
@@ -453,7 +454,7 @@ static void ui_but_user_menu_add(bContext *C, uiBut *but, bUserMenu *um)
static void popup_user_menu_add_or_replace_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = arg1;
bUserMenu *um = ED_screen_user_menu_ensure(C);
bUserMenu *um = ED_screen_user_menu_ensure(C, 0);
U.runtime.is_dirty = true;
ui_but_user_menu_add(C, but, um);
}
@@ -983,7 +984,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
bool item_found = false;
uint um_array_len;
bUserMenu **um_array = ED_screen_user_menus_find(C, &um_array_len);
bUserMenu **um_array = ED_screen_user_menus_find(C, &um_array_len, 0);
for (int um_index = 0; um_index < um_array_len; um_index++) {
bUserMenu *um = um_array[um_index];
if (um == NULL) {

View File

@@ -7390,3 +7390,80 @@ void uiTemplateFileSelectPath(uiLayout *layout, bContext *C, FileSelectParams *p
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Keymap Template
* \{ */
static void template_user_menu_item_properties(uiLayout *layout,
const char *title,
PointerRNA *ptr)
{
uiLayout *flow, *box, *row;
uiItemS(layout);
if (title) {
uiItemL(layout, title, ICON_NONE);
}
flow = uiLayoutColumnFlow(layout, 2, false);
int i = 0;
RNA_STRUCT_BEGIN_SKIP_RNA_TYPE (ptr, prop) {
const bool is_set = RNA_property_is_set(ptr, prop);
uiBut *but;
// recurse for nested properties
if (RNA_property_type(prop) == PROP_POINTER) {
PointerRNA propptr = RNA_property_pointer_get(ptr, prop);
if (propptr.data && RNA_struct_is_a(propptr.type, &RNA_OperatorProperties)) {
const char *name = RNA_property_ui_name(prop);
template_user_menu_item_properties(layout, name, &propptr);
continue;
}
}
box = uiLayoutBox(flow);
uiLayoutSetActive(box, is_set);
row = uiLayoutRow(box, false);
// property value
uiItemFullR(row, ptr, prop, -1, 0, 0, NULL, ICON_NONE);
if (is_set) {
// unset operator
uiBlock *block = uiLayoutGetBlock(row);
UI_block_emboss_set(block, UI_EMBOSS_NONE);
but = uiDefIconButO(block,
UI_BTYPE_BUT,
"UI_OT_unset_property_button",
WM_OP_EXEC_DEFAULT,
ICON_X,
0,
0,
UI_UNIT_X,
UI_UNIT_Y,
NULL);
but->rnapoin = *ptr;
but->rnaprop = prop;
UI_block_emboss_set(block, UI_EMBOSS);
}
}
RNA_STRUCT_END;
}
void uiTemplateUserMenuItemProperties(uiLayout *layout, PointerRNA *ptr)
{
PointerRNA propptr = RNA_pointer_get(ptr, "prop");
if (propptr.data) {
uiBut *but = uiLayoutGetBlock(layout)->buttons.last;
WM_operator_properties_sanitize(&propptr, false);
template_user_menu_item_properties(layout, NULL, &propptr);
}
}
/** \} */

View File

@@ -67,10 +67,23 @@ static const char *screen_menu_context_string(const bContext *C, const SpaceLink
/** \} */
/* -------------------------------------------------------------------- */
/** \name Menu Type
/** \name Menu Group
* \{ */
bUserMenu **ED_screen_user_menus_find(const bContext *C, uint *r_len)
bUserMenusGroup *ED_screen_user_menus_group_find(int id)
{
int index = 0;
LISTBASE_FOREACH (bUserMenusGroup *, umg, &U.user_menus_group) {
if (index == id)
return umg;
index++;
}
return NULL;
}
/** \} */
bUserMenu **ED_screen_user_menus_find_menu(const bContext *C, uint *r_len, bUserMenusGroup *umg)
{
SpaceLink *sl = CTX_wm_space_data(C);
@@ -83,23 +96,33 @@ bUserMenu **ED_screen_user_menus_find(const bContext *C, uint *r_len)
const char *context = screen_menu_context_string(C, sl);
uint array_len = 3;
bUserMenu **um_array = MEM_calloc_arrayN(array_len, sizeof(*um_array), __func__);
um_array[0] = BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context);
um_array[0] = BKE_blender_user_menu_find(&umg->menus, sl->spacetype, context);
um_array[1] = (sl->spacetype != SPACE_TOPBAR) ?
BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context_mode) :
BKE_blender_user_menu_find(&umg->menus, SPACE_TOPBAR, context_mode) :
NULL;
um_array[2] = (sl->spacetype == SPACE_VIEW3D) ?
BKE_blender_user_menu_find(&U.user_menus, SPACE_PROPERTIES, context_mode) :
BKE_blender_user_menu_find(&umg->menus, SPACE_PROPERTIES, context_mode) :
NULL;
*r_len = array_len;
return um_array;
}
bUserMenu *ED_screen_user_menu_ensure(bContext *C)
bUserMenu **ED_screen_user_menus_find(const bContext *C, uint *r_len, int id)
{
bUserMenusGroup *umg = ED_screen_user_menus_group_find(id);
if (!umg)
return NULL;
return ED_screen_user_menus_find_menu(C, r_len, umg);
}
bUserMenu *ED_screen_user_menu_ensure(bContext *C, int id)
{
bUserMenusGroup *umg = ED_screen_user_menus_group_find(id);
if (!umg)
return NULL;
SpaceLink *sl = CTX_wm_space_data(C);
const char *context = screen_menu_context_string(C, sl);
return BKE_blender_user_menu_ensure(&U.user_menus, sl->spacetype, context);
return BKE_blender_user_menu_ensure(&umg->menus, sl->spacetype, context);
}
/** \} */
@@ -169,6 +192,9 @@ void ED_screen_user_menu_item_add_operator(ListBase *lb,
STRNCPY(umi_op->item.ui_name, ui_name);
}
STRNCPY(umi_op->op_idname, ot->idname);
umi_op->ptr = NULL;
umi_op->prop = NULL;
WM_operator_properties_alloc(&(umi_op->ptr), &(umi_op->prop), ot->idname);
umi_op->prop = prop ? IDP_CopyProperty(prop) : NULL;
}
@@ -182,7 +208,8 @@ void ED_screen_user_menu_item_add_menu(ListBase *lb, const char *ui_name, const
STRNCPY(umi_mt->mt_idname, mt->idname);
}
void ED_screen_user_menu_item_add_prop(ListBase *lb,
void ED_screen_user_menu_item_add_prop(bContext *C,
ListBase *lb,
const char *ui_name,
const char *context_data_path,
const char *prop_id,
@@ -194,6 +221,39 @@ void ED_screen_user_menu_item_add_prop(ListBase *lb,
STRNCPY(umi_pr->context_data_path, context_data_path);
STRNCPY(umi_pr->prop_id, prop_id);
umi_pr->prop_index = prop_index;
/* Copy current context name into ui_name if null */
if (ui_name && ui_name[0] != '\0')
return;
char *data_path = strchr(umi_pr->context_data_path, '.');
if (data_path) {
*data_path = '\0';
}
PointerRNA ptr = CTX_data_pointer_get(C, umi_pr->context_data_path);
if (ptr.type == NULL) {
PointerRNA ctx_ptr;
RNA_pointer_create(NULL, &RNA_Context, (void *)C, &ctx_ptr);
if (!RNA_path_resolve_full(&ctx_ptr, umi_pr->context_data_path, &ptr, NULL, NULL)) {
ptr.type = NULL;
}
}
if (data_path) {
*data_path = '.';
data_path += 1;
}
if (ptr.type != NULL) {
PropertyRNA *prop = NULL;
PointerRNA prop_ptr = ptr;
if ((data_path == NULL) || RNA_path_resolve_full(&ptr, data_path, &prop_ptr, NULL, NULL)) {
prop = RNA_struct_find_property(&prop_ptr, umi_pr->prop_id);
}
if (prop) {
const char *name = RNA_property_ui_name(prop);
BLI_strncpy(umi_pr->item.ui_name, name, FILE_MAX);
}
}
}
void ED_screen_user_menu_item_remove(ListBase *lb, bUserMenuItem *umi)
@@ -208,97 +268,146 @@ void ED_screen_user_menu_item_remove(ListBase *lb, bUserMenuItem *umi)
/** \name Menu Definition
* \{ */
static void screen_user_menu_draw(const bContext *C, Menu *menu)
static void screen_user_menu_draw_submenu(bContext *C, uiLayout *layout, void *arg)
{
ListBase *lb = (ListBase *)arg;
screen_user_menu_draw_items(C, layout, lb, false);
}
bool screen_user_menu_draw_items(const bContext *C, uiLayout *layout, ListBase *lb, char type)
{
/* Enable when we have the ability to edit menus. */
const bool show_missing = false;
char label[512];
const bool show_missing = type;
bool is_empty = true;
int i = 0;
LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
if (type == 1 && i > 7)
return is_empty;
const char *ui_name = umi->ui_name[0] ? umi->ui_name : NULL;
if (umi->type == USER_MENU_TYPE_OPERATOR) {
bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
wmOperatorType *ot = WM_operatortype_find(umi_op->op_idname, false);
if (ot != NULL) {
IDProperty *prop = umi_op->prop ? IDP_CopyProperty(umi_op->prop) : NULL;
uiItemFullO_ptr(layout, ot, ui_name, umi->icon, prop, umi_op->opcontext, 0, NULL);
is_empty = false;
}
else {
if (show_missing) {
SNPRINTF(label, "Missing: %s", umi_op->op_idname);
uiItemL(layout, label, ICON_NONE);
}
i--;
}
}
else if (umi->type == USER_MENU_TYPE_MENU) {
bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
MenuType *mt = WM_menutype_find(umi_mt->mt_idname, false);
if (mt != NULL) {
uiItemM_ptr(layout, mt, ui_name, umi->icon);
is_empty = false;
}
else {
if (show_missing) {
SNPRINTF(label, "Missing: %s", umi_mt->mt_idname);
uiItemL(layout, label, ICON_NONE);
}
i--;
}
}
else if (umi->type == USER_MENU_TYPE_SUBMENU) {
bUserMenuItem_SubMenu *umi_mt = (bUserMenuItem_SubMenu *)umi;
uiItemMenuF(
layout, ui_name, umi->icon, &screen_user_menu_draw_submenu, (void *)&umi_mt->items);
is_empty = false;
}
else if (umi->type == USER_MENU_TYPE_PROP) {
bUserMenuItem_Prop *umi_pr = (bUserMenuItem_Prop *)umi;
char *data_path = strchr(umi_pr->context_data_path, '.');
if (data_path) {
*data_path = '\0';
}
PointerRNA ptr = CTX_data_pointer_get(C, umi_pr->context_data_path);
if (ptr.type == NULL) {
PointerRNA ctx_ptr;
RNA_pointer_create(NULL, &RNA_Context, (void *)C, &ctx_ptr);
if (!RNA_path_resolve_full(&ctx_ptr, umi_pr->context_data_path, &ptr, NULL, NULL)) {
ptr.type = NULL;
}
}
if (data_path) {
*data_path = '.';
data_path += 1;
}
bool ok = false;
if (ptr.type != NULL) {
PropertyRNA *prop = NULL;
PointerRNA prop_ptr = ptr;
if ((data_path == NULL) || RNA_path_resolve_full(&ptr, data_path, &prop_ptr, NULL, NULL)) {
prop = RNA_struct_find_property(&prop_ptr, umi_pr->prop_id);
if (prop) {
ok = true;
uiItemFullR(layout, &prop_ptr, prop, umi_pr->prop_index, 0, 0, ui_name, umi->icon);
is_empty = false;
}
}
}
if (!ok) {
if (show_missing) {
SNPRINTF(label, "Missing: %s.%s", umi_pr->context_data_path, umi_pr->prop_id);
uiItemL(layout, label, ICON_NONE);
}
i--;
}
}
else if (umi->type == USER_MENU_TYPE_SEP) {
uiItemS(layout);
}
i++;
}
return is_empty;
}
void screen_user_menu_draw_begin(bContext *C, uiLayout *layout, char type, bUserMenusGroup *umg)
{
uint um_array_len;
bUserMenu **um_array = ED_screen_user_menus_find(C, &um_array_len);
bUserMenu **um_array = ED_screen_user_menus_find_menu(C, &um_array_len, umg);
bool is_empty = true;
for (int um_index = 0; um_index < um_array_len; um_index++) {
bUserMenu *um = um_array[um_index];
if (um == NULL) {
continue;
}
LISTBASE_FOREACH (bUserMenuItem *, umi, &um->items) {
const char *ui_name = umi->ui_name[0] ? umi->ui_name : NULL;
if (umi->type == USER_MENU_TYPE_OPERATOR) {
bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
wmOperatorType *ot = WM_operatortype_find(umi_op->op_idname, false);
if (ot != NULL) {
IDProperty *prop = umi_op->prop ? IDP_CopyProperty(umi_op->prop) : NULL;
uiItemFullO_ptr(menu->layout, ot, ui_name, ICON_NONE, prop, umi_op->opcontext, 0, NULL);
is_empty = false;
}
else {
if (show_missing) {
SNPRINTF(label, "Missing: %s", umi_op->op_idname);
uiItemL(menu->layout, label, ICON_NONE);
}
}
}
else if (umi->type == USER_MENU_TYPE_MENU) {
bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
MenuType *mt = WM_menutype_find(umi_mt->mt_idname, false);
if (mt != NULL) {
uiItemM_ptr(menu->layout, mt, ui_name, ICON_NONE);
is_empty = false;
}
else {
if (show_missing) {
SNPRINTF(label, "Missing: %s", umi_mt->mt_idname);
uiItemL(menu->layout, label, ICON_NONE);
}
}
}
else if (umi->type == USER_MENU_TYPE_PROP) {
bUserMenuItem_Prop *umi_pr = (bUserMenuItem_Prop *)umi;
is_empty = screen_user_menu_draw_items(C, layout, &um->items, true) && is_empty;
}
if (um_array) {
MEM_freeN(um_array);
}
char *data_path = strchr(umi_pr->context_data_path, '.');
if (data_path) {
*data_path = '\0';
}
PointerRNA ptr = CTX_data_pointer_get(C, umi_pr->context_data_path);
if (ptr.type == NULL) {
PointerRNA ctx_ptr;
RNA_pointer_create(NULL, &RNA_Context, (void *)C, &ctx_ptr);
if (!RNA_path_resolve_full(&ctx_ptr, umi_pr->context_data_path, &ptr, NULL, NULL)) {
ptr.type = NULL;
}
}
if (data_path) {
*data_path = '.';
data_path += 1;
}
if (is_empty && type == 0) {
uiItemL(layout, TIP_("No menu items found"), ICON_NONE);
uiItemL(layout, TIP_("Right click on buttons to add them to this menu"), ICON_NONE);
}
}
bool ok = false;
if (ptr.type != NULL) {
PropertyRNA *prop = NULL;
PointerRNA prop_ptr = ptr;
if ((data_path == NULL) ||
RNA_path_resolve_full(&ptr, data_path, &prop_ptr, NULL, NULL)) {
prop = RNA_struct_find_property(&prop_ptr, umi_pr->prop_id);
if (prop) {
ok = true;
uiItemFullR(
menu->layout, &prop_ptr, prop, umi_pr->prop_index, 0, 0, ui_name, ICON_NONE);
is_empty = false;
}
}
}
if (!ok) {
if (show_missing) {
SNPRINTF(label, "Missing: %s.%s", umi_pr->context_data_path, umi_pr->prop_id);
uiItemL(menu->layout, label, ICON_NONE);
}
}
}
else if (umi->type == USER_MENU_TYPE_SEP) {
uiItemS(menu->layout);
}
static void screen_user_menu_draw(const bContext *C, Menu *menu)
{
uint um_array_len;
bUserMenu **um_array = ED_screen_user_menus_find(C, &um_array_len, 0);
bool is_empty = true;
for (int um_index = 0; um_index < um_array_len; um_index++) {
bUserMenu *um = um_array[um_index];
if (um == NULL) {
continue;
}
is_empty = is_empty || screen_user_menu_draw_items(C, menu->layout, &um->items, true);
}
if (um_array) {
MEM_freeN(um_array);

View File

@@ -136,6 +136,7 @@ static void userpref_main_region_layout(const bContext *C, ARegion *region)
i = 0;
}
const char *id = items[i].identifier;
BLI_assert(strlen(id) < sizeof(id_lower));
STRNCPY(id_lower, id);
BLI_str_tolower_ascii(id_lower, strlen(id_lower));

View File

@@ -515,27 +515,42 @@ typedef struct bPathCompare {
char _pad0[7];
} bPathCompare;
typedef struct bUserMenusGroup {
struct bUserMenusGroup *next, *prev;
/* bUserMenu */
char idname[64];
char name[64];
char type;
char _pad0[7];
struct ListBase menus;
} bUserMenusGroup;
typedef struct bUserMenu {
struct bUserMenu *next, *prev;
char space_type;
char _pad0[7];
char context[64];
/* bUserMenuItem */
ListBase items;
struct ListBase items;
} bUserMenu;
/** May be part of #bUserMenu or other list. */
typedef struct bUserMenuItem {
struct bUserMenuItem *next, *prev;
struct bUserMenuItem_SubMenu *parent;
int icon;
char ui_name[64];
char type;
char _pad0[7];
// editor
char is_selected;
char _pad0[2];
} bUserMenuItem;
typedef struct bUserMenuItem_Op {
bUserMenuItem item;
char op_idname[64];
struct IDProperty *prop;
struct PointerRNA *ptr;
char opcontext;
char _pad0[7];
} bUserMenuItem_Op;
@@ -545,6 +560,12 @@ typedef struct bUserMenuItem_Menu {
char mt_idname[64];
} bUserMenuItem_Menu;
typedef struct bUserMenuItem_SubMenu {
bUserMenuItem item;
struct ListBase items;
char name[64];
} bUserMenuItem_SubMenu;
typedef struct bUserMenuItem_Prop {
bUserMenuItem item;
char context_data_path[256];
@@ -558,6 +579,7 @@ enum {
USER_MENU_TYPE_OPERATOR = 2,
USER_MENU_TYPE_MENU = 3,
USER_MENU_TYPE_PROP = 4,
USER_MENU_TYPE_SUBMENU = 5,
};
typedef struct SolidLight {
@@ -582,7 +604,14 @@ typedef struct WalkNavigation {
typedef struct UserDef_Runtime {
char is_dirty;
char _pad0[7];
/* User menu editor runtime datas */
char um_space_select;
char um_context_select;
char um_expanded;
char _pad0[4];
struct bUserMenuItem *um_item_select;
struct bUserMenusGroup *umg_select;
} UserDef_Runtime;
/**
@@ -722,8 +751,10 @@ typedef struct UserDef {
struct ListBase user_keyconfig_prefs;
struct ListBase addons;
struct ListBase autoexec_paths;
/** #bUserMenu. */
/** #bUserMenu : deprecated, keep for compatibility. */
struct ListBase user_menus;
/** #bUserMenuGroups. */
struct ListBase user_menus_group;
char keyconfigstr[64];
@@ -913,16 +944,17 @@ typedef enum eUserPref_Section {
USER_SECTION_ADDONS = 6,
USER_SECTION_LIGHT = 7,
USER_SECTION_KEYMAP = 8,
USER_SECTION_USER_MENUS = 9,
#ifdef WITH_USERDEF_WORKSPACES
USER_SECTION_WORKSPACE_CONFIG = 9,
USER_SECTION_WORKSPACE_ADDONS = 10,
USER_SECTION_WORKSPACE_KEYMAPS = 11,
USER_SECTION_WORKSPACE_CONFIG = 10,
USER_SECTION_WORKSPACE_ADDONS = 11,
USER_SECTION_WORKSPACE_KEYMAPS = 12,
#endif
USER_SECTION_VIEWPORT = 12,
USER_SECTION_ANIMATION = 13,
USER_SECTION_NAVIGATION = 14,
USER_SECTION_FILE_PATHS = 15,
USER_SECTION_EXPERIMENTAL = 16,
USER_SECTION_VIEWPORT = 13,
USER_SECTION_ANIMATION = 14,
USER_SECTION_NAVIGATION = 15,
USER_SECTION_FILE_PATHS = 16,
USER_SECTION_EXPERIMENTAL = 17,
} eUserPref_Section;
/** #UserDef_SpaceData.flag (State of the user preferences UI). */

View File

@@ -474,6 +474,7 @@ extern StructRNA RNA_PreferencesEdit;
extern StructRNA RNA_PreferencesFilePaths;
extern StructRNA RNA_PreferencesInput;
extern StructRNA RNA_PreferencesKeymap;
extern StructRNA RNA_PreferencesUserMenus;
extern StructRNA RNA_PreferencesSystem;
extern StructRNA RNA_PreferencesView;
extern StructRNA RNA_Property;

View File

@@ -1869,7 +1869,7 @@ void RNA_def_property_enum_items(PropertyRNA *prop, const EnumPropertyItem *item
{
StructRNA *srna = DefRNA.laststruct;
int i, defaultfound = 0;
switch (prop->type) {
case PROP_ENUM: {
EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop;

View File

@@ -1639,6 +1639,12 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_property_ui_text(parm, "Item", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
api_ui_item_common_text(func);
/* User menu template */
func = RNA_def_function(
srna, "template_user_menu_item_properties", "uiTemplateUserMenuItemProperties");
parm = RNA_def_pointer(func, "item", "um_item_op", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
}
#endif

View File

@@ -88,6 +88,7 @@ const EnumPropertyItem rna_enum_preference_section_items[] = {
{USER_SECTION_INPUT, "INPUT", 0, "Input", ""},
{USER_SECTION_NAVIGATION, "NAVIGATION", 0, "Navigation", ""},
{USER_SECTION_KEYMAP, "KEYMAP", 0, "Keymap", ""},
{USER_SECTION_USER_MENUS, "USER_MENUS", 0, "User Menus", ""},
{0, "", 0, NULL, NULL},
{USER_SECTION_SYSTEM, "SYSTEM", 0, "System", ""},
{USER_SECTION_SAVE_LOAD, "SAVE_LOAD", 0, "Save & Load", ""},
@@ -177,6 +178,7 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = {
# include "DNA_screen_types.h"
# include "BKE_blender.h"
# include "BKE_blender_user_menu.h"
# include "BKE_global.h"
# include "BKE_idprop.h"
# include "BKE_image.h"
@@ -186,6 +188,8 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = {
# include "BKE_pbvh.h"
# include "BKE_screen.h"
# include "ED_screen.h"
# include "DEG_depsgraph.h"
# include "GPU_extensions.h"
@@ -531,6 +535,11 @@ static PointerRNA rna_UserDef_keymap_get(PointerRNA *ptr)
return rna_pointer_inherit_refine(ptr, &RNA_PreferencesKeymap, ptr->data);
}
static PointerRNA rna_UserDef_user_menus_get(PointerRNA *ptr)
{
return rna_pointer_inherit_refine(ptr, &RNA_PreferencesUserMenus, ptr->data);
}
static PointerRNA rna_UserDef_filepaths_get(PointerRNA *ptr)
{
return rna_pointer_inherit_refine(ptr, &RNA_PreferencesFilePaths, ptr->data);
@@ -1068,6 +1077,549 @@ static void rna_UserDef_studiolight_light_ambient_get(PointerRNA *ptr, float *va
copy_v3_v3(values, sl->light_ambient);
}
/* User Menus Functions */
static bUserMenu *rna_UserDef_usermenus_get_current(UserDef *userdef, bool ensure)
{
const char **contexts_list = CTX_data_list_mode_string();
# if 0 /* UNUSED */
ListBase *umg_list = &userdef->user_menus_group;
# endif
bUserMenusGroup *umg = userdef->runtime.umg_select;
bUserMenu *bum = NULL;
if (!umg)
return NULL;
if (userdef->runtime.um_space_select > 0) {
if (umg->type) {
bum = BKE_blender_user_menu_find(&umg->menus,
userdef->runtime.um_space_select,
contexts_list[userdef->runtime.um_context_select]);
if (!bum) {
bum = BKE_blender_user_menu_ensure(&umg->menus,
userdef->runtime.um_space_select,
contexts_list[userdef->runtime.um_context_select]);
for (int i = 0; i < 8; i++) {
BKE_blender_user_menu_item_add(&bum->items, USER_MENU_TYPE_SEP);
}
}
}
else {
if (ensure) {
bum = BKE_blender_user_menu_ensure(&umg->menus,
userdef->runtime.um_space_select,
contexts_list[userdef->runtime.um_context_select]);
}
else {
bum = BKE_blender_user_menu_find(&umg->menus,
userdef->runtime.um_space_select,
contexts_list[userdef->runtime.um_context_select]);
}
}
}
return bum;
}
/*static bUserMenuItem *rna_UserDef_usermenus_get_current_item(UserDef *userdef)
{
int id = userdef->runtime.um_item_select - 1;
if (id < 0) return NULL;
bUserMenu *bum = rna_UserDef_usermenus_get_current(userdef, false);
if (bum) {
ListBase *lb = &bum->items;
int i = 0;
for (bUserMenuItem *umi = lb->first; umi; umi = umi->next, i++) {
if (i == id)
return umi;
}
}
return NULL;
}*/
static bUserMenusGroup *rna_UserDef_usermenus_get_group(UserDef *userdef, const char *idname)
{
return BKE_blender_user_menus_group_find(&userdef->user_menus_group, idname);
}
static void rna_UserDef_usermenus_set_group(UserDef *userdef, bUserMenusGroup *umg)
{
userdef->runtime.umg_select = umg;
}
static void rna_UserDef_usermenus_add_group(UserDef *userdef)
{
bUserMenusGroup *umg = BKE_blender_user_menus_group_new("new menu");
BLI_addtail(&userdef->user_menus_group, umg);
userdef->runtime.umg_select = umg;
}
static void rna_UserDef_usermenus_remove_group(UserDef *userdef)
{
bUserMenusGroup *umg = userdef->runtime.umg_select;
userdef->runtime.umg_select = umg->prev;
if (!userdef->runtime.umg_select) {
userdef->runtime.umg_select = umg->next;
if (!userdef->runtime.umg_select) {
return;
}
}
BLI_remlink(&userdef->user_menus_group, umg);
BKE_blender_user_menu_free_list(&umg->menus);
MEM_freeN(umg);
}
static bool rna_UserDef_usermenus_has_item(UserDef *userdef)
{
bUserMenu *bum = rna_UserDef_usermenus_get_current(userdef, false);
if (!bum)
return false;
ListBase *lb = &bum->items;
bUserMenuItem *umi = lb->first;
if (!umi)
return false;
return true;
}
static int rna_UserDef_usermenus_items_length(UserDef *userdef)
{
bUserMenu *bum = rna_UserDef_usermenus_get_current(userdef, false);
if (!bum)
return 0;
ListBase *lb = &bum->items;
int i = 0;
for (bUserMenuItem *umi = lb->first; umi; umi = umi->next, i++)
;
return i;
}
static int rna_UserDef_usermenus_spacetypes_get(PointerRNA *ptr)
{
UserDef *userdef = (UserDef *)ptr->data;
int id = userdef->runtime.um_space_select;
id = (id <= 0) ? USER_SECTION_EDITING : id;
return id;
}
static void rna_UserDef_usermenus_active_item_set(PointerRNA *ptr, bool value)
{
bUserMenuItem *umi = (bUserMenuItem *)ptr->data;
if (value) {
U.runtime.um_item_select = umi;
}
umi->is_selected = value;
}
static const EnumPropertyItem *rna_UserDef_usermenus_spacetypes_itemf(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
bool *r_free)
{
int totitem = 0;
EnumPropertyItem *item = NULL;
int i;
const ListBase *spacetypes = BKE_spacetypes_list();
SpaceType *st = NULL;
for (i = 0, st = spacetypes->first; st; st = st->next, i++) {
int id = st->spaceid;
EnumPropertyItem new_item = {id, st->name, 0, st->name, st->name};
RNA_enum_item_add(&item, &totitem, &new_item);
}
# ifndef NDEBUG
if (i == 0) {
EnumPropertyItem new_item = {i, "NO_SPACETYPE", 0, "No spacetype available", ""};
RNA_enum_item_add(&item, &totitem, &new_item);
}
# endif
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
static const EnumPropertyItem *rna_UserDef_usermenus_contexts_itemf(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
bool *r_free)
{
static const char *contexts_list[] = {
"mesh edit", "curve edit", "surface edit", "text edit",
"armature edit", "mball edit", "lattice edit", "pose mode",
"sculpt mode", "weight paint", "vertex paint", "image paint",
"particle mode", "object mode", "greasepencil paint", "greasepencil edit",
"greasepencil sculpt", "greasepencil weight", "greasepencil vertex", NULL,
};
int totitem = 0;
EnumPropertyItem *item = NULL;
int i;
for (i = 0; contexts_list[i]; i++) {
EnumPropertyItem new_item = {i, contexts_list[i], 0, contexts_list[i], contexts_list[i]};
RNA_enum_item_add(&item, &totitem, &new_item);
}
# ifndef NDEBUG
if (i == 0) {
EnumPropertyItem new_item = {i, "NO_CONTEXT", 0, "No context available", ""};
RNA_enum_item_add(&item, &totitem, &new_item);
}
# endif
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
static const EnumPropertyItem *rna_UserDef_icons_itemf(bContext *UNUSED(C),
PointerRNA *UNUSED(ptr),
PropertyRNA *UNUSED(prop),
bool *r_free)
{
int totitem = 0;
const EnumPropertyItem *list = rna_enum_icon_items;
EnumPropertyItem *item = NULL;
int i;
for (i = 0; list[i].identifier; i++) {
EnumPropertyItem new_item = {
list[i].value, list[i].identifier, list[i].value, list[i].name, list[i].description};
RNA_enum_item_add(&item, &totitem, &new_item);
}
# ifndef NDEBUG
if (i == 0) {
EnumPropertyItem new_item = {i, "NONE", 0, "No icons", ""};
RNA_enum_item_add(&item, &totitem, &new_item);
}
# endif
RNA_enum_item_end(&item, &totitem);
*r_free = true;
return item;
}
static void rna_UserDef_usermenus_item_add(UserDef *userdef, int index)
{
bUserMenu *um = rna_UserDef_usermenus_get_current(userdef, true);
if (!um)
return;
ListBase *lb = &um->items;
bUserMenuItem_Op *umi = (bUserMenuItem_Op *)BKE_blender_user_menu_item_add(
NULL, USER_MENU_TYPE_OPERATOR);
if (index < 0)
BLI_addtail(lb, umi);
else {
int i = 0;
for (bUserMenuItem *insert = lb->first; insert; insert = insert->next, i++) {
if (i == index) {
BLI_insertlinkbefore(lb, insert, umi);
return;
}
}
BLI_addtail(lb, umi);
}
// basic operator setup
wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_add", true);
STRNCPY(umi->item.ui_name, "new item");
STRNCPY(umi->op_idname, ot->idname);
userdef->runtime.um_item_select = &umi->item;
}
static void rna_UserDef_usermenus_item_remove(UserDef *userdef)
{
bUserMenu *bum = rna_UserDef_usermenus_get_current(userdef, true);
bUserMenuItem *umi = userdef->runtime.um_item_select;
if (!bum || !umi)
return;
userdef->runtime.um_item_select = umi->next;
if (!userdef->runtime.um_item_select)
userdef->runtime.um_item_select = umi->prev;
ListBase *lb = (umi->parent) ? &umi->parent->items : &bum->items;
ED_screen_user_menu_item_remove(lb, umi);
}
static void rna_UserDef_usermenus_item_move(UserDef *userdef, bool up)
{
bUserMenu *bum = rna_UserDef_usermenus_get_current(userdef, true);
bUserMenuItem *umi = userdef->runtime.um_item_select;
if (!bum || !umi)
return;
ListBase *lb = (umi->parent) ? &umi->parent->items : &bum->items;
bUserMenuItem *umi_toward = (up) ? umi->prev : umi->next;
BLI_remlink(lb, umi);
if (!umi_toward) {
if (!umi->parent)
return;
if (!umi->parent->item.parent) {
if (up)
BLI_insertlinkbefore(&bum->items, umi->parent, umi);
else
BLI_insertlinkafter(&bum->items, umi->parent, umi);
umi->parent = NULL;
}
else {
if (up)
BLI_insertlinkbefore(&umi->parent->item.parent->items, umi->parent, umi);
else
BLI_insertlinkafter(&umi->parent->item.parent->items, umi->parent, umi);
umi->parent = umi->parent->item.parent;
}
}
else if (umi_toward->type == USER_MENU_TYPE_SUBMENU) {
bUserMenuItem_SubMenu *umi_sm = (bUserMenuItem_SubMenu *)umi_toward;
if (up)
BLI_addtail(&umi_sm->items, umi);
else
BLI_addhead(&umi_sm->items, umi);
umi->parent = umi_sm;
}
else {
if (up)
BLI_insertlinkbefore(lb, umi->prev, umi);
else
BLI_insertlinkafter(lb, umi->next, umi);
}
}
static void rna_UserDef_usermenus_pie_item_add(UserDef *userdef, int index)
{
bUserMenu *um = rna_UserDef_usermenus_get_current(userdef, true);
if (!um)
return;
bUserMenuItem_Op *umi = NULL;
ListBase *lb = &um->items;
bUserMenuItem *insert = lb->first;
int i = 0;
for (insert = lb->first; insert; insert = insert->next, i++) {
if (insert->type != USER_MENU_TYPE_SUBMENU)
continue;
bUserMenuItem_SubMenu *sm = (bUserMenuItem_SubMenu *)insert;
if (i == index) {
umi = (bUserMenuItem_Op *)BKE_blender_user_menu_item_add(&sm->items,
USER_MENU_TYPE_OPERATOR);
break;
}
}
if (!umi)
return;
// basic operator setup
wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_add", true);
STRNCPY(umi->item.ui_name, "new item");
STRNCPY(umi->op_idname, ot->idname);
umi->item.parent = (bUserMenuItem_SubMenu *)insert;
userdef->runtime.um_item_select = &umi->item;
}
static void rna_UserDef_usermenus_item_type_set(PointerRNA *ptr, int value)
{
bUserMenuItem *umi = (bUserMenuItem *)ptr->data;
bUserMenu *bum = rna_UserDef_usermenus_get_current(&U, true);
if (!bum || !umi || umi->type == value)
return;
ListBase *lb = (!umi->parent) ? &bum->items : &umi->parent->items;
BLI_remlink(lb, umi);
bUserMenuItem *new_umi = BKE_blender_user_menu_item_add(NULL, value);
new_umi->parent = umi->parent;
if (value == USER_MENU_TYPE_SUBMENU) {
bUserMenuItem_SubMenu *umi_sm = (bUserMenuItem_SubMenu *)new_umi;
BLI_listbase_clear(&umi_sm->items);
}
BLI_insertlinkafter(lb, umi->prev, new_umi);
STRNCPY(new_umi->ui_name, umi->ui_name);
BKE_blender_user_menu_item_free(umi);
U.runtime.um_item_select = new_umi;
}
static int rna_UserDef_usermenus_item_type_get(PointerRNA *ptr)
{
bUserMenuItem *data = (bUserMenuItem *)(ptr->data);
if (data)
return (int)(data->type);
return 0;
}
static void rna_UserDef_usermenus_item_name_get(PointerRNA *ptr, char *value)
{
bUserMenuItem *umi = (bUserMenuItem *)(ptr->data);
if (!*umi->ui_name) {
const char *name = " ";
if (umi->type == USER_MENU_TYPE_MENU) {
bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
MenuType *mt = WM_menutype_find(umi_mt->mt_idname, true);
name = (const char *)CTX_IFACE_(mt->translation_context, mt->label);
BLI_strncpy(umi->ui_name, name, FILE_MAX);
}
}
BLI_strncpy(value, umi->ui_name, FILE_MAX);
}
static void rna_UserDef_usermenus_pie_set(PointerRNA *ptr, int value)
{
bUserMenusGroup *umg = (bUserMenusGroup *)ptr->data;
LISTBASE_FOREACH (bUserMenu *, um, &umg->menus) {
ListBase *lb = &um->items;
BKE_blender_user_menu_item_free_list(lb);
if (value)
for (int i = 0; i < 8; i++) {
BKE_blender_user_menu_item_add(lb, USER_MENU_TYPE_SEP);
}
}
umg->type = value;
}
static PointerRNA rna_UserDef_usermenus_item_op_prop_get(PointerRNA *ptr)
{
bUserMenuItem_Op *umi_op = ptr->data;
if (umi_op->ptr) {
return *(umi_op->ptr);
}
return PointerRNA_NULL;
}
static void rna_UserDef_usermenus_group_idname_set(Main *bmain,
Scene *UNUSED(scene),
PointerRNA *ptr)
{
bUserMenusGroup *umg = (bUserMenusGroup *)ptr->data;
# if 0
const char *name = umg->name;
# endif
char old[64] = {'\0'};
STRNCPY(old, umg->idname);
BKE_blender_user_menus_group_idname_update(umg);
BKE_blender_user_menus_group_idname_update_keymap(bmain->wm.first, old, umg->idname);
}
static void rna_UserDef_usermenus_item_op_get(PointerRNA *ptr, char *value)
{
bUserMenuItem_Op *umi_op = ptr->data;
WM_operator_py_idname(value, umi_op->op_idname);
}
static int rna_UserDef_usermenus_item_op_length(PointerRNA *ptr)
{
bUserMenuItem_Op *umi_op = ptr->data;
char pyname[OP_MAX_TYPENAME];
WM_operator_py_idname(pyname, umi_op->op_idname);
return strlen(pyname);
}
static void rna_UserDef_usermenus_item_op_set(PointerRNA *ptr, const char *value)
{
bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)ptr->data;
char idname_bl[OP_MAX_TYPENAME];
wmOperatorType *origin_ot = WM_operatortype_find(umi_op->op_idname, true);
wmOperatorType *ot = WM_operatortype_find(value, false);
if (origin_ot == ot || ot == NULL)
return;
WM_operator_bl_idname(idname_bl, value);
WM_operator_py_idname(umi_op->op_idname, value);
if (LIKELY(umi_op->ptr)) {
WM_operator_properties_free(umi_op->ptr);
MEM_freeN(umi_op->ptr);
umi_op->ptr = NULL;
}
umi_op->prop = NULL;
WM_operator_properties_alloc(&(umi_op->ptr), &(umi_op->prop), idname_bl);
WM_operator_properties_sanitize(umi_op->ptr, 1);
}
static void rna_UserDef_usermenu_draw(UserDef *UNUSED(userdef),
bContext *C,
uiLayout *layout,
bUserMenusGroup *umg)
{
screen_user_menu_draw_begin(C, layout, true, umg);
}
/* UserMenu.menu_items */
static void rna_UserDef_usermenu_items_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
bUserMenu *bum = (bUserMenu *)ptr->data;
rna_iterator_listbase_begin(iter, &bum->items, NULL);
}
static void rna_UserDef_usermenu_submenu_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
bUserMenuItem_SubMenu *umi_sm = (bUserMenuItem_SubMenu *)ptr->data;
rna_iterator_listbase_begin(iter, &umi_sm->items, NULL);
}
static bUserMenuItem_Op *rna_UserDef_usermenus_item_operator_get(bUserMenuItem *umi)
{
if (umi->type == USER_MENU_TYPE_OPERATOR)
return (bUserMenuItem_Op *)umi;
return NULL;
}
static bUserMenuItem_Menu *rna_UserDef_usermenus_item_menu_get(bUserMenuItem *umi)
{
if (umi->type == USER_MENU_TYPE_MENU)
return (bUserMenuItem_Menu *)umi;
return NULL;
}
static bUserMenuItem_Prop *rna_UserDef_usermenus_item_property_get(bUserMenuItem *umi)
{
if (umi->type == USER_MENU_TYPE_PROP)
return (bUserMenuItem_Prop *)umi;
return NULL;
}
static bUserMenuItem_SubMenu *rna_UserDef_usermenus_item_submenu_get(bUserMenuItem *umi)
{
if (umi->type == USER_MENU_TYPE_SUBMENU)
return (bUserMenuItem_SubMenu *)umi;
return NULL;
}
/* UserMenus.menus */
static void rna_UserDef_usermenu_menus_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
UserDef *userdef = (UserDef *)ptr->data;
rna_iterator_listbase_begin(iter, &userdef->user_menus_group, NULL);
}
int rna_show_statusbar_vram_editable(struct PointerRNA *UNUSED(ptr), const char **UNUSED(r_info))
{
return GPU_mem_stats_supported() ? PROP_EDITABLE : 0;
@@ -5910,6 +6462,384 @@ static void rna_def_userdef_keymap(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Key Config", "The name of the active key configuration");
}
static void rna_def_userdef_usermenus_items_subtypes(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
/* operator item */
srna = RNA_def_struct(brna, "um_item_op", NULL);
RNA_def_struct_sdna(srna, "bUserMenuItem_Op");
RNA_def_struct_ui_text(
srna, "User Menu operator item", "an item of the user menus that can store an operator");
prop = RNA_def_property(srna, "item", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "item");
RNA_def_property_struct_type(prop, "UserMenuItem");
RNA_def_property_ui_text(prop, "item", "");
prop = RNA_def_property(srna, "operator", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "op_idname");
RNA_def_property_ui_text(prop, "operator", "the operator that will be executed");
RNA_def_property_string_funcs(prop,
"rna_UserDef_usermenus_item_op_get",
"rna_UserDef_usermenus_item_op_length",
"rna_UserDef_usermenus_item_op_set");
RNA_def_struct_name_property(srna, prop);
prop = RNA_def_property(srna, "prop", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "prop");
RNA_def_property_struct_type(prop, "OperatorProperties");
RNA_def_property_ui_text(prop, "properties", "properties of the operator");
RNA_def_property_pointer_funcs(prop, "rna_UserDef_usermenus_item_op_prop_get", NULL, NULL, NULL);
/* menu item */
srna = RNA_def_struct(brna, "um_item_menu", NULL);
RNA_def_struct_sdna(srna, "bUserMenuItem_Menu");
RNA_def_struct_ui_text(
srna, "User Menu menu item", "an item of the user menus that can store a submenu");
prop = RNA_def_property(srna, "item", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "item");
RNA_def_property_struct_type(prop, "UserMenuItem");
RNA_def_property_ui_text(prop, "item", "");
prop = RNA_def_property(srna, "id_name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "mt_idname");
RNA_def_property_ui_text(prop, "id name", "the menu id name");
RNA_def_struct_name_property(srna, prop);
/* prop item */
srna = RNA_def_struct(brna, "um_item_prop", NULL);
RNA_def_struct_sdna(srna, "bUserMenuItem_Prop");
RNA_def_struct_ui_text(
srna, "User Menu property item", "an item of the user menus that can store a property");
prop = RNA_def_property(srna, "item", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "item");
RNA_def_property_struct_type(prop, "UserMenuItem");
RNA_def_property_ui_text(prop, "item", "");
prop = RNA_def_property(srna, "id_name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "prop_id");
RNA_def_property_ui_text(prop, "id name", "the property id name");
RNA_def_struct_name_property(srna, prop);
prop = RNA_def_property(srna, "context", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "context_data_path");
RNA_def_property_ui_text(prop, "context", "the context data path of the property");
RNA_def_struct_name_property(srna, prop);
/* sub menu item */
srna = RNA_def_struct(brna, "um_item_submenu", NULL);
RNA_def_struct_sdna(srna, "bUserMenuItem_SubMenu");
RNA_def_struct_ui_text(
srna, "User Menu sub menu item", "an item of the user menus that can store a sub menu");
prop = RNA_def_property(srna, "item", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "item");
RNA_def_property_struct_type(prop, "UserMenuItem");
RNA_def_property_ui_text(prop, "item", "");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_ui_text(prop, "name", "the sub menu name");
RNA_def_struct_name_property(srna, prop);
prop = RNA_def_property(srna, "items_list", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "UserMenuItem");
RNA_def_property_ui_text(prop, "sub menu items", "list of the items of the sub menu");
RNA_def_property_collection_funcs(prop,
"rna_UserDef_usermenu_submenu_begin",
"rna_iterator_listbase_next",
NULL,
"rna_iterator_listbase_get",
NULL,
NULL,
NULL,
NULL);
}
static void rna_def_userdef_usermenu(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
FunctionRNA *func;
PropertyRNA *parm;
/* user menu */
srna = RNA_def_struct(brna, "UserMenu", NULL);
RNA_def_struct_sdna(srna, "bUserMenu");
RNA_def_struct_ui_text(srna, "User Menu", "an user menu");
prop = RNA_def_property(srna, "spacetype", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "space_type");
RNA_def_property_ui_text(prop, "Space Type", "The Space type the user menu will be used in");
prop = RNA_def_property(srna, "context", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "context");
RNA_def_property_ui_text(prop, "Context", "The Context the user menu will be used in");
RNA_def_struct_name_property(srna, prop);
prop = RNA_def_property(srna, "menu_items", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "UserMenuItem");
RNA_def_property_ui_text(prop, "Items", "list of the items of the menu");
RNA_def_property_collection_funcs(prop,
"rna_UserDef_usermenu_items_begin",
"rna_iterator_listbase_next",
NULL,
"rna_iterator_listbase_get",
NULL,
NULL,
NULL,
NULL);
/* user menu item */
static const EnumPropertyItem um_item_type[] = {
{USER_MENU_TYPE_OPERATOR, "OPERATOR", 0, "Operator", "Operator"},
{USER_MENU_TYPE_PROP, "PROPERTY", 0, "Property", "Property"},
{USER_MENU_TYPE_SUBMENU, "SUBMENU", 0, "Menu", "Menu"},
{USER_MENU_TYPE_MENU, "MENU", 0, "Packed Menu", "Packed Menu"},
{USER_MENU_TYPE_SEP, "SEPARATOR", 0, "Separator", "Separator"},
{0, NULL, 0, NULL, NULL},
};
srna = RNA_def_struct(brna, "UserMenuItem", NULL);
RNA_def_struct_sdna(srna, "bUserMenuItem");
RNA_def_struct_ui_text(srna, "User Menu Item", "User Menu item");
prop = RNA_def_property(srna, "next", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "next");
RNA_def_property_struct_type(prop, "UserMenuItem");
RNA_def_property_ui_text(prop, "item", "");
prop = RNA_def_property(srna, "prev", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "prev");
RNA_def_property_struct_type(prop, "UserMenuItem");
RNA_def_property_ui_text(prop, "item", "");
prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "parent");
RNA_def_property_struct_type(prop, "um_item_submenu");
RNA_def_property_ui_text(prop, "item", "");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "ui_name");
RNA_def_property_string_funcs(prop, "rna_UserDef_usermenus_item_name_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Name", "Name of the item");
RNA_def_struct_name_property(srna, prop);
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, um_item_type);
RNA_def_property_enum_funcs(
prop, "rna_UserDef_usermenus_item_type_get", "rna_UserDef_usermenus_item_type_set", NULL);
RNA_def_property_ui_text(prop, "type", "the type of item");
prop = RNA_def_property(srna, "icon", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "icon");
RNA_def_property_enum_items(prop, rna_enum_icon_items);
RNA_def_property_enum_default(prop, ICON_NONE);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_UserDef_icons_itemf");
RNA_def_property_ui_text(prop, "Icon", "The item icon");
prop = RNA_def_property(srna, "is_selected", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "is_selected", 0);
RNA_def_property_ui_text(prop, "is selected", "is selected");
RNA_def_property_boolean_funcs(prop, NULL, "rna_UserDef_usermenus_active_item_set");
func = RNA_def_function(srna, "get_operator", "rna_UserDef_usermenus_item_operator_get");
RNA_def_function_ui_description(func, "return the operator item");
parm = RNA_def_pointer(func, "item_op", "um_item_op", "", "the item operator");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "get_menu", "rna_UserDef_usermenus_item_menu_get");
RNA_def_function_ui_description(func, "return the operator menu");
parm = RNA_def_pointer(func, "item_menu", "um_item_menu", "", "the item menu");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "get_property", "rna_UserDef_usermenus_item_property_get");
RNA_def_function_ui_description(func, "return the operator property");
parm = RNA_def_pointer(func, "item_prop", "um_item_prop", "", "the item property");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "get_submenu", "rna_UserDef_usermenus_item_submenu_get");
RNA_def_function_ui_description(func, "return the submenu");
parm = RNA_def_pointer(func, "item_submenu", "um_item_submenu", "", "the item submenu");
RNA_def_function_return(func, parm);
rna_def_userdef_usermenus_items_subtypes(brna);
}
static void rna_def_userdef_usermenusgroup(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
static const EnumPropertyItem um_menu_type[] = {
{0, "LIST", 0, "List", "List"},
{1, "PIE", 0, "Pie", "Pie"},
{0, NULL, 0, NULL, NULL},
};
/* user menus group */
srna = RNA_def_struct(brna, "UserMenusGroup", NULL);
RNA_def_struct_sdna(srna, "bUserMenusGroup");
RNA_def_struct_ui_text(srna, "User Menus Group", "A whole displayble user menu");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_ui_text(prop, "Name", "Name of the user menu group");
RNA_def_struct_name_property(srna, prop);
RNA_def_property_update(prop, 0, "rna_UserDef_usermenus_group_idname_set");
prop = RNA_def_property(srna, "idname", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "idname");
RNA_def_property_ui_text(prop, "ID Name", "ID Name of the user menu group");
RNA_def_struct_name_property(srna, prop);
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, um_menu_type);
RNA_def_property_ui_text(prop, "menu type", "change menu type between list and pie");
RNA_def_property_enum_funcs(prop, NULL, "rna_UserDef_usermenus_pie_set", NULL);
prop = RNA_def_property(srna, "menus", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "UserMenu");
RNA_def_property_ui_text(prop, "User Menu", "list of user sub menus contained in the group");
}
static void rna_def_userdef_usermenus_editor(BlenderRNA *brna)
{
PropertyRNA *prop;
FunctionRNA *func;
PropertyRNA *parm;
static const EnumPropertyItem um_space_default[] = {
{0, "NULL", 0, "None", "No spacetypes found"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem um_context_default[] = {
{0, "NULL", 0, "None", "No context found"},
{0, NULL, 0, NULL, NULL},
};
StructRNA *srna = RNA_def_struct(brna, "PreferencesUserMenus", NULL);
RNA_def_struct_sdna(srna, "UserDef");
RNA_def_struct_nested(brna, srna, "Preferences");
RNA_def_struct_clear_flag(srna, STRUCT_UNDO);
RNA_def_struct_ui_text(srna, "User Menus", "User Menus editor");
prop = RNA_def_property(srna, "space_selected", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "runtime.um_space_select");
RNA_def_property_enum_items(prop, um_space_default);
RNA_def_property_enum_funcs(prop,
"rna_UserDef_usermenus_spacetypes_get",
NULL,
"rna_UserDef_usermenus_spacetypes_itemf");
RNA_def_property_ui_text(prop, "space type selected", "the space type selected");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "context_selected", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "runtime.um_context_select");
RNA_def_property_enum_items(prop, um_context_default);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_UserDef_usermenus_contexts_itemf");
RNA_def_property_ui_text(prop, "context selected", "the context selected");
RNA_def_property_update(prop, 0, "rna_userdef_update");
prop = RNA_def_property(srna, "active_item", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "runtime.um_item_select");
RNA_def_property_struct_type(prop, "UserMenuItem");
RNA_def_property_ui_text(prop, "item", "");
prop = RNA_def_property(srna, "active_group", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_pointer_sdna(prop, NULL, "runtime.umg_select");
RNA_def_property_struct_type(prop, "UserMenusGroup");
RNA_def_property_ui_text(prop, "active user menus group", "active user menus group");
prop = RNA_def_property(srna, "menus", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "UserMenusGroup");
RNA_def_property_ui_text(prop, "Menus", "list of the menus");
RNA_def_property_collection_funcs(prop,
"rna_UserDef_usermenu_menus_begin",
"rna_iterator_listbase_next",
"rna_iterator_listbase_end",
"rna_iterator_listbase_get",
NULL,
NULL,
NULL,
NULL);
prop = RNA_def_property(srna, "expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "runtime.um_expanded", 0);
RNA_def_property_ui_text(prop, "Items Expanded", "Expanded in the user interface");
RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
rna_def_userdef_usermenu(brna);
rna_def_userdef_usermenusgroup(brna);
// functions
func = RNA_def_function(srna, "get_current_menu", "rna_UserDef_usermenus_get_current");
RNA_def_function_ui_description(func, "get active user menu");
parm = RNA_def_boolean(func, "ensure", false, "ensure", "create the menu if don't exist");
parm = RNA_def_pointer(func, "current_menu", "UserMenu", "", "the menu");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "get_group", "rna_UserDef_usermenus_get_group");
RNA_def_function_ui_description(func, "get user menus group by idname");
parm = RNA_def_string(func, "idname", NULL, 0, "ID name", "ID name of the group");
parm = RNA_def_pointer(func, "menu", "UserMenusGroup", "", "the menu group");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "set_group", "rna_UserDef_usermenus_set_group");
RNA_def_function_ui_description(func, "set the group menu to edit");
parm = RNA_def_pointer(func, "new_group", "UserMenusGroup", "", "the group menu");
func = RNA_def_function(srna, "add_group", "rna_UserDef_usermenus_add_group");
RNA_def_function_ui_description(func, "add a group");
func = RNA_def_function(srna, "remove_group", "rna_UserDef_usermenus_remove_group");
RNA_def_function_ui_description(func, "remove a group");
func = RNA_def_function(srna, "items_len", "rna_UserDef_usermenus_items_length");
RNA_def_function_ui_description(func, "Refresh custom menu editor");
parm = RNA_def_int(func, "len", 0, 0, 1000, "", "the list len", 0, 1000);
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "has_item", "rna_UserDef_usermenus_has_item");
RNA_def_function_ui_description(func, "the current list has items");
parm = RNA_def_boolean(func, "has_item", false, "", "is there items in the current list ?");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "item_add", "rna_UserDef_usermenus_item_add");
RNA_def_function_ui_description(func, "add an item to a menu");
parm = RNA_def_int(func, "index", 0, -1, 1000, "index", "index to insert the item", -1, 1000);
func = RNA_def_function(srna, "item_remove", "rna_UserDef_usermenus_item_remove");
RNA_def_function_ui_description(func, "remove an item from a user menu");
func = RNA_def_function(srna, "item_move", "rna_UserDef_usermenus_item_move");
RNA_def_function_ui_description(func, "up an item");
parm = RNA_def_boolean(func, "up", false, "", "go up ?");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
func = RNA_def_function(srna, "pie_item_add", "rna_UserDef_usermenus_pie_item_add");
RNA_def_function_ui_description(func, "add an item to a menu");
parm = RNA_def_int(func, "index", 0, -1, 1000, "index", "index to insert the item", -1, 1000);
func = RNA_def_function(srna, "draw_menu", "rna_UserDef_usermenu_draw");
RNA_def_function_ui_description(func, "draw items of usermenu");
parm = RNA_def_pointer(func, "context", "Context", "", "context");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "layout", "UILayout", "", "layout");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "menu", "UserMenusGroup", "", "menu");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
static void rna_def_userdef_filepaths(BlenderRNA *brna)
{
PropertyRNA *prop;
@@ -6248,6 +7178,12 @@ void RNA_def_userdef(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, "rna_UserDef_keymap_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Keymap", "Shortcut setup for keyboards and other input devices");
prop = RNA_def_property(srna, "user_menus", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "PreferencesUserMenus");
RNA_def_property_pointer_funcs(prop, "rna_UserDef_user_menus_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "User Menus", "User Menus Editor");
prop = RNA_def_property(srna, "filepaths", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "PreferencesFilePaths");
@@ -6315,6 +7251,7 @@ void RNA_def_userdef(BlenderRNA *brna)
rna_def_userdef_edit(brna);
rna_def_userdef_input(brna);
rna_def_userdef_keymap(brna);
rna_def_userdef_usermenus_editor(brna);
rna_def_userdef_filepaths(brna);
rna_def_userdef_system(brna);
rna_def_userdef_addon(brna);

View File

@@ -1841,6 +1841,8 @@ static void rna_struct_update_when_changed(bContext *C,
PointerRNA *ptr_b)
{
CollectionPropertyIterator iter;
if (!ptr_a->data || !ptr_b->data)
return;
PropertyRNA *iterprop = RNA_struct_iterator_property(ptr_a->type);
BLI_assert(ptr_a->type == ptr_b->type);
RNA_property_collection_begin(ptr_a, iterprop, &iter);