Blender V4.3
screen_user_menu.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cfloat>
10#include <cmath>
11#include <cstdio>
12#include <cstring>
13
14#include "DNA_scene_types.h"
15
16#include "MEM_guardedalloc.h"
17
18#include "BLI_listbase.h"
19#include "BLI_string.h"
20#include "BLI_utildefines.h"
21
22#include "BLT_translation.hh"
23
25#include "BKE_context.hh"
26#include "BKE_idprop.hh"
27#include "BKE_screen.hh"
28
29#include "WM_api.hh"
30#include "WM_types.hh"
31
32#include "ED_screen.hh"
33
34#include "UI_interface.hh"
35#include "UI_resources.hh"
36
37#include "RNA_access.hh"
38#include "RNA_path.hh"
39#include "RNA_prototypes.hh"
40
41/* -------------------------------------------------------------------- */
45static const char *screen_menu_context_string(const bContext *C, const SpaceLink *sl)
46{
47 if (sl->spacetype == SPACE_NODE) {
48 const SpaceNode *snode = (const SpaceNode *)sl;
49 return snode->tree_idname;
50 }
51 return CTX_data_mode_string(C);
52}
53
56/* -------------------------------------------------------------------- */
61{
63
64 if (sl == nullptr) {
65 *r_len = 0;
66 return nullptr;
67 }
68
69 const char *context_mode = CTX_data_mode_string(C);
70 const char *context = screen_menu_context_string(C, sl);
71 uint array_len = 3;
72 bUserMenu **um_array = static_cast<bUserMenu **>(
73 MEM_calloc_arrayN(array_len, sizeof(*um_array), __func__));
74 um_array[0] = BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context);
75 um_array[1] = (sl->spacetype != SPACE_TOPBAR) ?
76 BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context_mode) :
77 nullptr;
78 um_array[2] = (sl->spacetype == SPACE_VIEW3D) ?
79 BKE_blender_user_menu_find(&U.user_menus, SPACE_PROPERTIES, context_mode) :
80 nullptr;
81
82 *r_len = array_len;
83 return um_array;
84}
85
87{
89 const char *context = screen_menu_context_string(C, sl);
90 return BKE_blender_user_menu_ensure(&U.user_menus, sl->spacetype, context);
91}
92
95/* -------------------------------------------------------------------- */
100 const wmOperatorType *ot,
101 IDProperty *prop,
102 const char *op_prop_enum,
103 wmOperatorCallContext opcontext)
104{
105 LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
106 if (umi->type == USER_MENU_TYPE_OPERATOR) {
107 bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
108 const bool ok_idprop = prop ? IDP_EqualsProperties(prop, umi_op->prop) : true;
109 const bool ok_prop_enum = (umi_op->op_prop_enum[0] != '\0') ?
110 STREQ(umi_op->op_prop_enum, op_prop_enum) :
111 true;
112 if (STREQ(ot->idname, umi_op->op_idname) && (opcontext == umi_op->opcontext) && ok_idprop &&
113 ok_prop_enum)
114 {
115 return umi_op;
116 }
117 }
118 }
119 return nullptr;
120}
121
123{
124 LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
125 if (umi->type == USER_MENU_TYPE_MENU) {
126 bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
127 if (STREQ(mt->idname, umi_mt->mt_idname)) {
128 return umi_mt;
129 }
130 }
131 }
132 return nullptr;
133}
134
136 const char *context_data_path,
137 const char *prop_id,
138 int prop_index)
139{
140 LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
141 if (umi->type == USER_MENU_TYPE_PROP) {
142 bUserMenuItem_Prop *umi_pr = (bUserMenuItem_Prop *)umi;
143 if (STREQ(context_data_path, umi_pr->context_data_path) && STREQ(prop_id, umi_pr->prop_id) &&
144 (prop_index == umi_pr->prop_index))
145 {
146 return umi_pr;
147 }
148 }
149 }
150 return nullptr;
151}
152
154 const char *ui_name,
155 const wmOperatorType *ot,
156 const IDProperty *prop,
157 const char *op_prop_enum,
158 wmOperatorCallContext opcontext)
159{
162 umi_op->opcontext = opcontext;
163 if (!STREQ(ui_name, ot->name)) {
164 STRNCPY(umi_op->item.ui_name, ui_name);
165 }
166 STRNCPY(umi_op->op_idname, ot->idname);
167 STRNCPY(umi_op->op_prop_enum, op_prop_enum);
168 umi_op->prop = prop ? IDP_CopyProperty(prop) : nullptr;
169}
170
171void ED_screen_user_menu_item_add_menu(ListBase *lb, const char *ui_name, const MenuType *mt)
172{
175 if (!STREQ(ui_name, mt->label)) {
176 STRNCPY(umi_mt->item.ui_name, ui_name);
177 }
178 STRNCPY(umi_mt->mt_idname, mt->idname);
179}
180
182 const char *ui_name,
183 const char *context_data_path,
184 const char *prop_id,
185 int prop_index)
186{
189 STRNCPY(umi_pr->item.ui_name, ui_name);
190 STRNCPY(umi_pr->context_data_path, context_data_path);
191 STRNCPY(umi_pr->prop_id, prop_id);
192 umi_pr->prop_index = prop_index;
193}
194
200
203/* -------------------------------------------------------------------- */
207static void screen_user_menu_draw(const bContext *C, Menu *menu)
208{
209 /* Enable when we have the ability to edit menus. */
210 const bool show_missing = false;
211 char label[512];
212
213 uint um_array_len;
214 bUserMenu **um_array = ED_screen_user_menus_find(C, &um_array_len);
215 bool is_empty = true;
216 for (int um_index = 0; um_index < um_array_len; um_index++) {
217 bUserMenu *um = um_array[um_index];
218 if (um == nullptr) {
219 continue;
220 }
221 LISTBASE_FOREACH (bUserMenuItem *, umi, &um->items) {
222 const char *ui_name = umi->ui_name[0] ? umi->ui_name : nullptr;
223 if (umi->type == USER_MENU_TYPE_OPERATOR) {
224 bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
226 if (ot != nullptr) {
227 if (umi_op->op_prop_enum[0] == '\0') {
228 IDProperty *prop = umi_op->prop ? IDP_CopyProperty(umi_op->prop) : nullptr;
230 ot,
232 ICON_NONE,
233 prop,
236 nullptr);
237 }
238 else {
239 /* umi_op->prop could be used to set other properties but it's currently unsupported.
240 */
242 C,
243 ot,
244 umi_op->op_prop_enum,
246 ICON_NONE,
247 nullptr);
248 }
249 is_empty = false;
250 }
251 else {
252 if (show_missing) {
253 SNPRINTF(label, RPT_("Missing: %s"), umi_op->op_idname);
254 uiItemL(menu->layout, label, ICON_NONE);
255 }
256 }
257 }
258 else if (umi->type == USER_MENU_TYPE_MENU) {
259 bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
260 MenuType *mt = WM_menutype_find(umi_mt->mt_idname, false);
261 if (mt != nullptr) {
262 uiItemM_ptr(menu->layout, mt, ui_name, ICON_NONE);
263 is_empty = false;
264 }
265 else {
266 if (show_missing) {
267 SNPRINTF(label, RPT_("Missing: %s"), umi_mt->mt_idname);
268 uiItemL(menu->layout, label, ICON_NONE);
269 }
270 }
271 }
272 else if (umi->type == USER_MENU_TYPE_PROP) {
273 bUserMenuItem_Prop *umi_pr = (bUserMenuItem_Prop *)umi;
274
275 char *data_path = strchr(umi_pr->context_data_path, '.');
276 if (data_path) {
277 *data_path = '\0';
278 }
280 if (ptr.type == nullptr) {
281 PointerRNA ctx_ptr = RNA_pointer_create(nullptr, &RNA_Context, (void *)C);
282 if (!RNA_path_resolve_full(&ctx_ptr, umi_pr->context_data_path, &ptr, nullptr, nullptr))
283 {
284 ptr.type = nullptr;
285 }
286 }
287 if (data_path) {
288 *data_path = '.';
289 data_path += 1;
290 }
291
292 bool ok = false;
293 if (ptr.type != nullptr) {
294 PropertyRNA *prop = nullptr;
295 PointerRNA prop_ptr = ptr;
296 if ((data_path == nullptr) ||
297 RNA_path_resolve_full(&ptr, data_path, &prop_ptr, nullptr, nullptr))
298 {
299 prop = RNA_struct_find_property(&prop_ptr, umi_pr->prop_id);
300 if (prop) {
301 ok = true;
302 uiItemFullR(menu->layout,
303 &prop_ptr,
304 prop,
305 umi_pr->prop_index,
306 0,
308 ui_name,
309 ICON_NONE);
310 is_empty = false;
311 }
312 }
313 }
314 if (!ok) {
315 if (show_missing) {
316 SNPRINTF(label, RPT_("Missing: %s.%s"), umi_pr->context_data_path, umi_pr->prop_id);
317 uiItemL(menu->layout, label, ICON_NONE);
318 }
319 }
320 }
321 else if (umi->type == USER_MENU_TYPE_SEP) {
322 uiItemS(menu->layout);
323 }
324 }
325 }
326 if (um_array) {
327 MEM_freeN(um_array);
328 }
329
330 if (is_empty) {
331 uiItemL(menu->layout, RPT_("No menu items found"), ICON_NONE);
332 uiItemL(menu->layout, RPT_("Right click on buttons to add them to this menu"), ICON_NONE);
333 }
334}
335
337{
338 MenuType *mt = static_cast<MenuType *>(MEM_callocN(sizeof(MenuType), __func__));
339 STRNCPY(mt->idname, "SCREEN_MT_user_menu");
340 STRNCPY(mt->label, N_("Quick Favorites"));
343 WM_menutype_add(mt);
344}
345
bUserMenu * BKE_blender_user_menu_find(ListBase *lb, char space_type, const char *context)
bUserMenu * BKE_blender_user_menu_ensure(ListBase *lb, char space_type, const char *context)
void BKE_blender_user_menu_item_free(bUserMenuItem *umi)
bUserMenuItem * BKE_blender_user_menu_item_add(ListBase *lb, int type)
PointerRNA CTX_data_pointer_get(const bContext *C, const char *member)
const char * CTX_data_mode_string(const bContext *C)
SpaceLink * CTX_wm_space_data(const bContext *C)
IDProperty * IDP_CopyProperty(const IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition idprop.cc:861
bool IDP_EqualsProperties(const IDProperty *prop1, const IDProperty *prop2) ATTR_WARN_UNUSED_RESULT
Definition idprop.cc:984
#define LISTBASE_FOREACH(type, var, list)
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
unsigned int uint
#define STREQ(a, b)
#define RPT_(msgid)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_DEFAULT_BPYRNA
@ SPACE_TOPBAR
@ SPACE_NODE
@ SPACE_PROPERTIES
@ SPACE_VIEW3D
@ USER_MENU_TYPE_OPERATOR
@ USER_MENU_TYPE_SEP
@ USER_MENU_TYPE_PROP
@ USER_MENU_TYPE_MENU
Read Guarded memory(de)allocation.
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, const char *name, int icon, const char *placeholder=nullptr)
void uiItemS(uiLayout *layout)
void uiItemFullO_ptr(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, IDProperty *properties, wmOperatorCallContext context, eUI_Item_Flag flag, PointerRNA *r_opptr)
#define UI_ITEM_NONE
void uiItemM_ptr(uiLayout *layout, MenuType *mt, const char *name, int icon)
void uiItemMenuEnumFullO_ptr(uiLayout *layout, const bContext *C, wmOperatorType *ot, const char *propname, const char *name, int icon, PointerRNA *r_opptr)
wmOperatorCallContext
Definition WM_types.hh:216
unsigned int U
Definition btGjkEpa3.h:78
const char * label
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
PointerRNA RNA_pointer_create(ID *id, StructRNA *type, void *data)
bool RNA_path_resolve_full(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
Definition rna_path.cc:537
bUserMenu * ED_screen_user_menu_ensure(bContext *C)
static void screen_user_menu_draw(const bContext *C, Menu *menu)
bUserMenu ** ED_screen_user_menus_find(const bContext *C, uint *r_len)
bUserMenuItem_Op * ED_screen_user_menu_item_find_operator(ListBase *lb, const wmOperatorType *ot, IDProperty *prop, const char *op_prop_enum, wmOperatorCallContext opcontext)
bUserMenuItem_Prop * ED_screen_user_menu_item_find_prop(ListBase *lb, const char *context_data_path, const char *prop_id, int prop_index)
static const char * screen_menu_context_string(const bContext *C, const SpaceLink *sl)
void ED_screen_user_menu_register()
void ED_screen_user_menu_item_add_operator(ListBase *lb, const char *ui_name, const wmOperatorType *ot, const IDProperty *prop, const char *op_prop_enum, wmOperatorCallContext opcontext)
void ED_screen_user_menu_item_add_prop(ListBase *lb, const char *ui_name, const char *context_data_path, const char *prop_id, int prop_index)
void ED_screen_user_menu_item_add_menu(ListBase *lb, const char *ui_name, const MenuType *mt)
void ED_screen_user_menu_item_remove(ListBase *lb, bUserMenuItem *umi)
bUserMenuItem_Menu * ED_screen_user_menu_item_find_menu(ListBase *lb, const MenuType *mt)
char label[BKE_ST_MAXNAME]
char idname[BKE_ST_MAXNAME]
void(* draw)(const bContext *C, Menu *menu)
char translation_context[BKE_ST_MAXNAME]
uiLayout * layout
StructRNA * type
Definition RNA_types.hh:41
char tree_idname[64]
struct IDProperty * prop
const char * name
Definition WM_types.hh:990
const char * idname
Definition WM_types.hh:992
const char * translation_context
Definition WM_types.hh:994
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
bool WM_menutype_add(MenuType *mt)
MenuType * WM_menutype_find(const char *idname, bool quiet)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)