Blender  V2.93
screen_user_menu.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include <float.h>
25 #include <math.h>
26 #include <stdio.h>
27 #include <string.h>
28 
29 #include "DNA_scene_types.h"
30 
31 #include "MEM_guardedalloc.h"
32 
33 #include "BLI_listbase.h"
34 #include "BLI_string.h"
35 #include "BLI_utildefines.h"
36 
37 #include "BLT_translation.h"
38 
39 #include "BKE_blender_user_menu.h"
40 #include "BKE_context.h"
41 #include "BKE_idprop.h"
42 #include "BKE_screen.h"
43 
44 #include "WM_api.h"
45 #include "WM_types.h"
46 
47 #include "ED_screen.h"
48 
49 #include "UI_interface.h"
50 #include "UI_resources.h"
51 
52 #include "RNA_access.h"
53 
54 /* -------------------------------------------------------------------- */
58 static const char *screen_menu_context_string(const bContext *C, const SpaceLink *sl)
59 {
60  if (sl->spacetype == SPACE_NODE) {
61  const SpaceNode *snode = (const SpaceNode *)sl;
62  return snode->tree_idname;
63  }
64  return CTX_data_mode_string(C);
65 }
66 
69 /* -------------------------------------------------------------------- */
74 {
76 
77  if (sl == NULL) {
78  *r_len = 0;
79  return NULL;
80  }
81 
82  const char *context_mode = CTX_data_mode_string(C);
83  const char *context = screen_menu_context_string(C, sl);
84  uint array_len = 3;
85  bUserMenu **um_array = MEM_calloc_arrayN(array_len, sizeof(*um_array), __func__);
86  um_array[0] = BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context);
87  um_array[1] = (sl->spacetype != SPACE_TOPBAR) ?
88  BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context_mode) :
89  NULL;
90  um_array[2] = (sl->spacetype == SPACE_VIEW3D) ?
91  BKE_blender_user_menu_find(&U.user_menus, SPACE_PROPERTIES, context_mode) :
92  NULL;
93 
94  *r_len = array_len;
95  return um_array;
96 }
97 
99 {
101  const char *context = screen_menu_context_string(C, sl);
102  return BKE_blender_user_menu_ensure(&U.user_menus, sl->spacetype, context);
103 }
104 
107 /* -------------------------------------------------------------------- */
112  const wmOperatorType *ot,
113  IDProperty *prop,
114  short opcontext)
115 {
116  LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
117  if (umi->type == USER_MENU_TYPE_OPERATOR) {
118  bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
119  if (STREQ(ot->idname, umi_op->op_idname) && (opcontext == umi_op->opcontext) &&
120  (IDP_EqualsProperties(prop, umi_op->prop))) {
121  return umi_op;
122  }
123  }
124  }
125  return NULL;
126 }
127 
129  const struct MenuType *mt)
130 {
131  LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
132  if (umi->type == USER_MENU_TYPE_MENU) {
133  bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
134  if (STREQ(mt->idname, umi_mt->mt_idname)) {
135  return umi_mt;
136  }
137  }
138  }
139  return NULL;
140 }
141 
143  const char *context_data_path,
144  const char *prop_id,
145  int prop_index)
146 {
147  LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
148  if (umi->type == USER_MENU_TYPE_PROP) {
149  bUserMenuItem_Prop *umi_pr = (bUserMenuItem_Prop *)umi;
150  if (STREQ(context_data_path, umi_pr->context_data_path) && STREQ(prop_id, umi_pr->prop_id) &&
151  (prop_index == umi_pr->prop_index)) {
152  return umi_pr;
153  }
154  }
155  }
156  return NULL;
157 }
158 
160  const char *ui_name,
161  const wmOperatorType *ot,
162  const IDProperty *prop,
163  short opcontext)
164 {
167  umi_op->opcontext = opcontext;
168  if (!STREQ(ui_name, ot->name)) {
169  STRNCPY(umi_op->item.ui_name, ui_name);
170  }
171  STRNCPY(umi_op->op_idname, ot->idname);
172  umi_op->prop = prop ? IDP_CopyProperty(prop) : NULL;
173 }
174 
175 void ED_screen_user_menu_item_add_menu(ListBase *lb, const char *ui_name, const MenuType *mt)
176 {
178  lb, USER_MENU_TYPE_MENU);
179  if (!STREQ(ui_name, mt->label)) {
180  STRNCPY(umi_mt->item.ui_name, ui_name);
181  }
182  STRNCPY(umi_mt->mt_idname, mt->idname);
183 }
184 
186  const char *ui_name,
187  const char *context_data_path,
188  const char *prop_id,
189  int prop_index)
190 {
192  lb, USER_MENU_TYPE_PROP);
193  STRNCPY(umi_pr->item.ui_name, ui_name);
195  STRNCPY(umi_pr->prop_id, prop_id);
196  umi_pr->prop_index = prop_index;
197 }
198 
200 {
201  BLI_remlink(lb, umi);
203 }
204 
207 /* -------------------------------------------------------------------- */
211 static void screen_user_menu_draw(const bContext *C, Menu *menu)
212 {
213  /* Enable when we have the ability to edit menus. */
214  const bool show_missing = false;
215  char label[512];
216 
217  uint um_array_len;
218  bUserMenu **um_array = ED_screen_user_menus_find(C, &um_array_len);
219  bool is_empty = true;
220  for (int um_index = 0; um_index < um_array_len; um_index++) {
221  bUserMenu *um = um_array[um_index];
222  if (um == NULL) {
223  continue;
224  }
225  LISTBASE_FOREACH (bUserMenuItem *, umi, &um->items) {
226  const char *ui_name = umi->ui_name[0] ? umi->ui_name : NULL;
227  if (umi->type == USER_MENU_TYPE_OPERATOR) {
228  bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
229  wmOperatorType *ot = WM_operatortype_find(umi_op->op_idname, false);
230  if (ot != NULL) {
231  IDProperty *prop = umi_op->prop ? IDP_CopyProperty(umi_op->prop) : NULL;
232  uiItemFullO_ptr(menu->layout, ot, ui_name, ICON_NONE, prop, umi_op->opcontext, 0, NULL);
233  is_empty = false;
234  }
235  else {
236  if (show_missing) {
237  SNPRINTF(label, "Missing: %s", umi_op->op_idname);
238  uiItemL(menu->layout, label, ICON_NONE);
239  }
240  }
241  }
242  else if (umi->type == USER_MENU_TYPE_MENU) {
243  bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
244  MenuType *mt = WM_menutype_find(umi_mt->mt_idname, false);
245  if (mt != NULL) {
246  uiItemM_ptr(menu->layout, mt, ui_name, ICON_NONE);
247  is_empty = false;
248  }
249  else {
250  if (show_missing) {
251  SNPRINTF(label, "Missing: %s", umi_mt->mt_idname);
252  uiItemL(menu->layout, label, ICON_NONE);
253  }
254  }
255  }
256  else if (umi->type == USER_MENU_TYPE_PROP) {
257  bUserMenuItem_Prop *umi_pr = (bUserMenuItem_Prop *)umi;
258 
259  char *data_path = strchr(umi_pr->context_data_path, '.');
260  if (data_path) {
261  *data_path = '\0';
262  }
264  if (ptr.type == NULL) {
265  PointerRNA ctx_ptr;
266  RNA_pointer_create(NULL, &RNA_Context, (void *)C, &ctx_ptr);
267  if (!RNA_path_resolve_full(&ctx_ptr, umi_pr->context_data_path, &ptr, NULL, NULL)) {
268  ptr.type = NULL;
269  }
270  }
271  if (data_path) {
272  *data_path = '.';
273  data_path += 1;
274  }
275 
276  bool ok = false;
277  if (ptr.type != NULL) {
278  PropertyRNA *prop = NULL;
279  PointerRNA prop_ptr = ptr;
280  if ((data_path == NULL) ||
281  RNA_path_resolve_full(&ptr, data_path, &prop_ptr, NULL, NULL)) {
282  prop = RNA_struct_find_property(&prop_ptr, umi_pr->prop_id);
283  if (prop) {
284  ok = true;
285  uiItemFullR(
286  menu->layout, &prop_ptr, prop, umi_pr->prop_index, 0, 0, ui_name, ICON_NONE);
287  is_empty = false;
288  }
289  }
290  }
291  if (!ok) {
292  if (show_missing) {
293  SNPRINTF(label, "Missing: %s.%s", umi_pr->context_data_path, umi_pr->prop_id);
294  uiItemL(menu->layout, label, ICON_NONE);
295  }
296  }
297  }
298  else if (umi->type == USER_MENU_TYPE_SEP) {
299  uiItemS(menu->layout);
300  }
301  }
302  }
303  if (um_array) {
304  MEM_freeN(um_array);
305  }
306 
307  if (is_empty) {
308  uiItemL(menu->layout, TIP_("No menu items found"), ICON_NONE);
309  uiItemL(menu->layout, TIP_("Right click on buttons to add them to this menu"), ICON_NONE);
310  }
311 }
312 
314 {
315  MenuType *mt = MEM_callocN(sizeof(MenuType), __func__);
316  strcpy(mt->idname, "SCREEN_MT_user_menu");
317  strcpy(mt->label, N_("Quick Favorites"));
320  WM_menutype_add(mt);
321 }
322 
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:445
const char * CTX_data_mode_string(const bContext *C)
struct SpaceLink * CTX_wm_space_data(const bContext *C)
Definition: context.c:719
bool IDP_EqualsProperties(struct IDProperty *prop1, struct IDProperty *prop2) ATTR_WARN_UNUSED_RESULT
Definition: idprop.c:875
struct IDProperty * IDP_CopyProperty(const struct IDProperty *prop) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
#define STRNCPY(dst, src)
Definition: BLI_string.h:163
#define SNPRINTF(dst, format,...)
Definition: BLI_string.h:165
unsigned int uint
Definition: BLI_sys_types.h:83
#define STREQ(a, b)
#define TIP_(msgid)
#define BLT_I18NCONTEXT_DEFAULT_BPYRNA
#define N_(msgid)
@ 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.
StructRNA RNA_Context
#define C
Definition: RandGen.cpp:39
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, int 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)
unsigned int U
Definition: btGjkEpa3.h:78
const char * label
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:46
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
Definition: rna_access.c:5416
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
bUserMenuItem_Op * ED_screen_user_menu_item_find_operator(ListBase *lb, const wmOperatorType *ot, IDProperty *prop, short opcontext)
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)
void ED_screen_user_menu_item_add_operator(ListBase *lb, const char *ui_name, const wmOperatorType *ot, const IDProperty *prop, short opcontext)
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)
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)
struct SELECTID_Context context
Definition: select_engine.c:47
char label[BKE_ST_MAXNAME]
Definition: BKE_screen.h:376
char idname[BKE_ST_MAXNAME]
Definition: BKE_screen.h:375
void(* draw)(const struct bContext *C, struct Menu *menu)
Definition: BKE_screen.h:384
char translation_context[BKE_ST_MAXNAME]
Definition: BKE_screen.h:377
struct uiLayout * layout
Definition: BKE_screen.h:392
struct StructRNA * type
Definition: RNA_types.h:51
char tree_idname[64]
bUserMenuItem item
struct IDProperty * prop
ListBase items
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
PointerRNA * ptr
Definition: wm_files.c:3157
wmOperatorType * ot
Definition: wm_files.c:3156
MenuType * WM_menutype_find(const char *idname, bool quiet)
Definition: wm_menu_type.c:44
bool WM_menutype_add(MenuType *mt)
Definition: wm_menu_type.c:65
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)