Blender  V3.3
screen_user_menu.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2009 Blender Foundation. All rights reserved. */
3 
8 #include <float.h>
9 #include <math.h>
10 #include <stdio.h>
11 #include <string.h>
12 
13 #include "DNA_scene_types.h"
14 
15 #include "MEM_guardedalloc.h"
16 
17 #include "BLI_listbase.h"
18 #include "BLI_string.h"
19 #include "BLI_utildefines.h"
20 
21 #include "BLT_translation.h"
22 
23 #include "BKE_blender_user_menu.h"
24 #include "BKE_context.h"
25 #include "BKE_idprop.h"
26 #include "BKE_screen.h"
27 
28 #include "WM_api.h"
29 #include "WM_types.h"
30 
31 #include "ED_screen.h"
32 
33 #include "UI_interface.h"
34 #include "UI_resources.h"
35 
36 #include "RNA_access.h"
37 #include "RNA_path.h"
38 #include "RNA_prototypes.h"
39 
40 /* -------------------------------------------------------------------- */
44 static const char *screen_menu_context_string(const bContext *C, const SpaceLink *sl)
45 {
46  if (sl->spacetype == SPACE_NODE) {
47  const SpaceNode *snode = (const SpaceNode *)sl;
48  return snode->tree_idname;
49  }
50  return CTX_data_mode_string(C);
51 }
52 
55 /* -------------------------------------------------------------------- */
60 {
62 
63  if (sl == NULL) {
64  *r_len = 0;
65  return NULL;
66  }
67 
68  const char *context_mode = CTX_data_mode_string(C);
69  const char *context = screen_menu_context_string(C, sl);
70  uint array_len = 3;
71  bUserMenu **um_array = MEM_calloc_arrayN(array_len, sizeof(*um_array), __func__);
72  um_array[0] = BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context);
73  um_array[1] = (sl->spacetype != SPACE_TOPBAR) ?
74  BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context_mode) :
75  NULL;
76  um_array[2] = (sl->spacetype == SPACE_VIEW3D) ?
77  BKE_blender_user_menu_find(&U.user_menus, SPACE_PROPERTIES, context_mode) :
78  NULL;
79 
80  *r_len = array_len;
81  return um_array;
82 }
83 
85 {
87  const char *context = screen_menu_context_string(C, sl);
88  return BKE_blender_user_menu_ensure(&U.user_menus, sl->spacetype, context);
89 }
90 
93 /* -------------------------------------------------------------------- */
98  const wmOperatorType *ot,
99  IDProperty *prop,
100  wmOperatorCallContext opcontext)
101 {
102  LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
103  if (umi->type == USER_MENU_TYPE_OPERATOR) {
104  bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
105  if (STREQ(ot->idname, umi_op->op_idname) && (opcontext == umi_op->opcontext) &&
106  (IDP_EqualsProperties(prop, umi_op->prop))) {
107  return umi_op;
108  }
109  }
110  }
111  return NULL;
112 }
113 
115  const struct MenuType *mt)
116 {
117  LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
118  if (umi->type == USER_MENU_TYPE_MENU) {
119  bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
120  if (STREQ(mt->idname, umi_mt->mt_idname)) {
121  return umi_mt;
122  }
123  }
124  }
125  return NULL;
126 }
127 
129  const char *context_data_path,
130  const char *prop_id,
131  int prop_index)
132 {
133  LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
134  if (umi->type == USER_MENU_TYPE_PROP) {
135  bUserMenuItem_Prop *umi_pr = (bUserMenuItem_Prop *)umi;
136  if (STREQ(context_data_path, umi_pr->context_data_path) && STREQ(prop_id, umi_pr->prop_id) &&
137  (prop_index == umi_pr->prop_index)) {
138  return umi_pr;
139  }
140  }
141  }
142  return NULL;
143 }
144 
146  const char *ui_name,
147  const wmOperatorType *ot,
148  const IDProperty *prop,
149  wmOperatorCallContext opcontext)
150 {
153  umi_op->opcontext = opcontext;
154  if (!STREQ(ui_name, ot->name)) {
155  STRNCPY(umi_op->item.ui_name, ui_name);
156  }
157  STRNCPY(umi_op->op_idname, ot->idname);
158  umi_op->prop = prop ? IDP_CopyProperty(prop) : NULL;
159 }
160 
161 void ED_screen_user_menu_item_add_menu(ListBase *lb, const char *ui_name, const MenuType *mt)
162 {
164  lb, USER_MENU_TYPE_MENU);
165  if (!STREQ(ui_name, mt->label)) {
166  STRNCPY(umi_mt->item.ui_name, ui_name);
167  }
168  STRNCPY(umi_mt->mt_idname, mt->idname);
169 }
170 
172  const char *ui_name,
173  const char *context_data_path,
174  const char *prop_id,
175  int prop_index)
176 {
178  lb, USER_MENU_TYPE_PROP);
179  STRNCPY(umi_pr->item.ui_name, ui_name);
181  STRNCPY(umi_pr->prop_id, prop_id);
182  umi_pr->prop_index = prop_index;
183 }
184 
186 {
187  BLI_remlink(lb, umi);
189 }
190 
193 /* -------------------------------------------------------------------- */
197 static void screen_user_menu_draw(const bContext *C, Menu *menu)
198 {
199  /* Enable when we have the ability to edit menus. */
200  const bool show_missing = false;
201  char label[512];
202 
203  uint um_array_len;
204  bUserMenu **um_array = ED_screen_user_menus_find(C, &um_array_len);
205  bool is_empty = true;
206  for (int um_index = 0; um_index < um_array_len; um_index++) {
207  bUserMenu *um = um_array[um_index];
208  if (um == NULL) {
209  continue;
210  }
211  LISTBASE_FOREACH (bUserMenuItem *, umi, &um->items) {
212  const char *ui_name = umi->ui_name[0] ? umi->ui_name : NULL;
213  if (umi->type == USER_MENU_TYPE_OPERATOR) {
214  bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
215  wmOperatorType *ot = WM_operatortype_find(umi_op->op_idname, false);
216  if (ot != NULL) {
217  IDProperty *prop = umi_op->prop ? IDP_CopyProperty(umi_op->prop) : NULL;
218  uiItemFullO_ptr(menu->layout,
219  ot,
220  CTX_IFACE_(ot->translation_context, ui_name),
221  ICON_NONE,
222  prop,
223  umi_op->opcontext,
224  0,
225  NULL);
226  is_empty = false;
227  }
228  else {
229  if (show_missing) {
230  SNPRINTF(label, TIP_("Missing: %s"), umi_op->op_idname);
231  uiItemL(menu->layout, label, ICON_NONE);
232  }
233  }
234  }
235  else if (umi->type == USER_MENU_TYPE_MENU) {
236  bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
237  MenuType *mt = WM_menutype_find(umi_mt->mt_idname, false);
238  if (mt != NULL) {
239  uiItemM_ptr(menu->layout, mt, ui_name, ICON_NONE);
240  is_empty = false;
241  }
242  else {
243  if (show_missing) {
244  SNPRINTF(label, TIP_("Missing: %s"), umi_mt->mt_idname);
245  uiItemL(menu->layout, label, ICON_NONE);
246  }
247  }
248  }
249  else if (umi->type == USER_MENU_TYPE_PROP) {
250  bUserMenuItem_Prop *umi_pr = (bUserMenuItem_Prop *)umi;
251 
252  char *data_path = strchr(umi_pr->context_data_path, '.');
253  if (data_path) {
254  *data_path = '\0';
255  }
257  if (ptr.type == NULL) {
258  PointerRNA ctx_ptr;
259  RNA_pointer_create(NULL, &RNA_Context, (void *)C, &ctx_ptr);
260  if (!RNA_path_resolve_full(&ctx_ptr, umi_pr->context_data_path, &ptr, NULL, NULL)) {
261  ptr.type = NULL;
262  }
263  }
264  if (data_path) {
265  *data_path = '.';
266  data_path += 1;
267  }
268 
269  bool ok = false;
270  if (ptr.type != NULL) {
271  PropertyRNA *prop = NULL;
272  PointerRNA prop_ptr = ptr;
273  if ((data_path == NULL) ||
274  RNA_path_resolve_full(&ptr, data_path, &prop_ptr, NULL, NULL)) {
275  prop = RNA_struct_find_property(&prop_ptr, umi_pr->prop_id);
276  if (prop) {
277  ok = true;
278  uiItemFullR(
279  menu->layout, &prop_ptr, prop, umi_pr->prop_index, 0, 0, ui_name, ICON_NONE);
280  is_empty = false;
281  }
282  }
283  }
284  if (!ok) {
285  if (show_missing) {
286  SNPRINTF(label, TIP_("Missing: %s.%s"), umi_pr->context_data_path, umi_pr->prop_id);
287  uiItemL(menu->layout, label, ICON_NONE);
288  }
289  }
290  }
291  else if (umi->type == USER_MENU_TYPE_SEP) {
292  uiItemS(menu->layout);
293  }
294  }
295  }
296  if (um_array) {
297  MEM_freeN(um_array);
298  }
299 
300  if (is_empty) {
301  uiItemL(menu->layout, TIP_("No menu items found"), ICON_NONE);
302  uiItemL(menu->layout, TIP_("Right click on buttons to add them to this menu"), ICON_NONE);
303  }
304 }
305 
307 {
308  MenuType *mt = MEM_callocN(sizeof(MenuType), __func__);
309  strcpy(mt->idname, "SCREEN_MT_user_menu");
310  strcpy(mt->label, N_("Quick Favorites"));
313  WM_menutype_add(mt);
314 }
315 
struct bUserMenu * BKE_blender_user_menu_ensure(struct ListBase *lb, char space_type, const char *context)
void BKE_blender_user_menu_item_free(struct bUserMenuItem *umi)
struct bUserMenu * BKE_blender_user_menu_find(struct ListBase *lb, char space_type, const char *context)
struct bUserMenuItem * BKE_blender_user_menu_item_add(struct ListBase *lb, int type)
PointerRNA CTX_data_pointer_get(const bContext *C, const char *member)
Definition: context.c:462
const char * CTX_data_mode_string(const bContext *C)
struct SpaceLink * CTX_wm_space_data(const bContext *C)
Definition: context.c:743
bool IDP_EqualsProperties(struct IDProperty *prop1, struct IDProperty *prop2) ATTR_WARN_UNUSED_RESULT
Definition: idprop.c:882
struct IDProperty * IDP_CopyProperty(const struct IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
#define STRNCPY(dst, src)
Definition: BLI_string.h:483
#define SNPRINTF(dst, format,...)
Definition: BLI_string.h:485
unsigned int uint
Definition: BLI_sys_types.h:67
#define STREQ(a, b)
#define TIP_(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.
#define C
Definition: RandGen.cpp:25
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemS(uiLayout *layout)
void uiItemFullO_ptr(uiLayout *layout, struct wmOperatorType *ot, const char *name, int icon, struct IDProperty *properties, wmOperatorCallContext context, int flag, struct PointerRNA *r_opptr)
void uiItemM_ptr(uiLayout *layout, struct MenuType *mt, const char *name, int icon)
void uiItemFullR(uiLayout *layout, struct PointerRNA *ptr, struct PropertyRNA *prop, int index, int value, int flag, const char *name, int icon)
wmOperatorCallContext
Definition: WM_types.h:199
unsigned int U
Definition: btGjkEpa3.h:78
const char * label
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:32
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:136
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
bool RNA_path_resolve_full(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
Definition: rna_path.cc:515
void ED_screen_user_menu_register(void)
struct bUserMenuItem_Prop * ED_screen_user_menu_item_find_prop(struct ListBase *lb, const char *context_data_path, const char *prop_id, int prop_index)
struct bUserMenuItem_Menu * ED_screen_user_menu_item_find_menu(struct ListBase *lb, const struct MenuType *mt)
static void screen_user_menu_draw(const bContext *C, Menu *menu)
bUserMenu * ED_screen_user_menu_ensure(bContext *C)
bUserMenu ** ED_screen_user_menus_find(const bContext *C, uint *r_len)
static const char * screen_menu_context_string(const bContext *C, const SpaceLink *sl)
bUserMenuItem_Op * ED_screen_user_menu_item_find_operator(ListBase *lb, const wmOperatorType *ot, IDProperty *prop, 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)
void ED_screen_user_menu_item_add_operator(ListBase *lb, const char *ui_name, const wmOperatorType *ot, const IDProperty *prop, wmOperatorCallContext opcontext)
char label[BKE_ST_MAXNAME]
Definition: BKE_screen.h:362
char idname[BKE_ST_MAXNAME]
Definition: BKE_screen.h:361
void(* draw)(const struct bContext *C, struct Menu *menu)
Definition: BKE_screen.h:370
char translation_context[BKE_ST_MAXNAME]
Definition: BKE_screen.h:363
struct uiLayout * layout
Definition: BKE_screen.h:378
struct StructRNA * type
Definition: RNA_types.h:37
char tree_idname[64]
bUserMenuItem item
struct IDProperty * prop
ListBase items
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
const char * translation_context
Definition: WM_types.h:891
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
MenuType * WM_menutype_find(const char *idname, bool quiet)
Definition: wm_menu_type.c:30
bool WM_menutype_add(MenuType *mt)
Definition: wm_menu_type.c:51
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)