UI: support adding menu's to favourites
[blender.git] / source / blender / editors / screen / screen_user_menu.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2009 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/screen/screen_user_menu.c
28  *  \ingroup spview3d
29  */
30
31 #include <string.h>
32 #include <stdio.h>
33 #include <math.h>
34 #include <float.h>
35
36 #include "DNA_scene_types.h"
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BLI_utildefines.h"
41 #include "BLI_listbase.h"
42 #include "BLI_string.h"
43
44 #include "BLT_translation.h"
45
46 #include "BKE_blender_user_menu.h"
47 #include "BKE_context.h"
48 #include "BKE_screen.h"
49 #include "BKE_idprop.h"
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53
54 #include "ED_screen.h"
55
56 #include "UI_interface.h"
57 #include "UI_resources.h"
58
59 /* -------------------------------------------------------------------- */
60 /** \name Menu Type
61  * \{ */
62
63 bUserMenu *ED_screen_user_menu_find(bContext *C)
64 {
65         SpaceLink *sl = CTX_wm_space_data(C);
66         const char *context = CTX_data_mode_string(C);
67         return BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context);
68 }
69
70 bUserMenu *ED_screen_user_menu_ensure(bContext *C)
71 {
72         SpaceLink *sl = CTX_wm_space_data(C);
73         const char *context = CTX_data_mode_string(C);
74         return BKE_blender_user_menu_ensure(&U.user_menus, sl->spacetype, context);
75 }
76
77 /** \} */
78
79 /* -------------------------------------------------------------------- */
80 /** \name Menu Item
81  * \{ */
82
83 bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(
84         ListBase *lb,
85         const wmOperatorType *ot, IDProperty *prop, short opcontext)
86 {
87         for (bUserMenuItem *umi = lb->first; umi; umi = umi->next) {
88                 if (umi->type == USER_MENU_TYPE_OPERATOR) {
89                         bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
90                         if (STREQ(ot->idname, umi_op->opname) &&
91                             (opcontext == umi_op->opcontext) &&
92                             (IDP_EqualsProperties(prop, umi_op->prop)))
93                         {
94                                 return umi_op;
95                         }
96                 }
97         }
98         return NULL;
99 }
100
101 struct bUserMenuItem_Menu *ED_screen_user_menu_item_find_menu(
102         struct ListBase *lb,
103         const struct MenuType *mt)
104 {
105         for (bUserMenuItem *umi = lb->first; umi; umi = umi->next) {
106                 if (umi->type == USER_MENU_TYPE_MENU) {
107                         bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
108                         if (STREQ(mt->idname, umi_mt->mt_idname)) {
109                                 return umi_mt;
110                         }
111                 }
112         }
113         return NULL;
114 }
115
116 void ED_screen_user_menu_item_add_operator(
117         ListBase *lb, const char *ui_name,
118         const wmOperatorType *ot, const IDProperty *prop, short opcontext)
119 {
120         bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)BKE_blender_user_menu_item_add(lb, USER_MENU_TYPE_OPERATOR);
121         umi_op->opcontext = opcontext;
122         if (!STREQ(ui_name, ot->name)) {
123                 STRNCPY(umi_op->item.ui_name, ui_name);
124         }
125         STRNCPY(umi_op->opname, ot->idname);
126         umi_op->prop = prop ? IDP_CopyProperty(prop) : NULL;
127 }
128
129 void ED_screen_user_menu_item_add_menu(
130         ListBase *lb, const char *ui_name,
131         const MenuType *mt)
132 {
133         bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)BKE_blender_user_menu_item_add(lb, USER_MENU_TYPE_MENU);
134         if (!STREQ(ui_name, mt->idname)) {
135                 STRNCPY(umi_mt->item.ui_name, ui_name);
136         }
137         STRNCPY(umi_mt->mt_idname, mt->idname);
138 }
139
140 void ED_screen_user_menu_item_remove(ListBase *lb, bUserMenuItem *umi)
141 {
142         BLI_remlink(lb, umi);
143         BKE_blender_user_menu_item_free(umi);
144 }
145
146 /** \} */
147
148 /* -------------------------------------------------------------------- */
149 /** \name Menu Definition
150  * \{ */
151
152 static void screen_user_menu_draw(const bContext *C, Menu *menu)
153 {
154         SpaceLink *sl = CTX_wm_space_data(C);
155         const char *context = CTX_data_mode_string(C);
156         bUserMenu *um_array[] = {
157                 BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context),
158                 (sl->spacetype != SPACE_TOPBAR) ? BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context) : NULL,
159         };
160         for (int um_index = 0; um_index < ARRAY_SIZE(um_array); um_index++) {
161                 bUserMenu *um = um_array[um_index];
162                 if (um == NULL) {
163                         continue;
164                 }
165                 for (bUserMenuItem *umi = um->items.first; umi; umi = umi->next) {
166                         if (umi->type == USER_MENU_TYPE_OPERATOR) {
167                                 bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
168                                 IDProperty *prop = umi_op->prop ? IDP_CopyProperty(umi_op->prop) : NULL;
169                                 uiItemFullO(
170                                         menu->layout, umi_op->opname, umi->ui_name[0] ? umi->ui_name : NULL,
171                                         ICON_NONE, prop, umi_op->opcontext, 0, NULL);
172                         }
173                         else if (umi->type == USER_MENU_TYPE_MENU) {
174                                 bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
175                                 uiItemM(
176                                         menu->layout, NULL, umi_mt->mt_idname, umi->ui_name[0] ? umi->ui_name : NULL,
177                                         ICON_NONE);
178                         }
179                         else if (umi->type == USER_MENU_TYPE_SEP) {
180                                 uiItemS(menu->layout);
181                         }
182                 }
183         }
184 }
185
186 void ED_screen_user_menu_register(void)
187 {
188         MenuType *mt = MEM_callocN(sizeof(MenuType), __func__);
189         strcpy(mt->idname, "SCREEN_MT_user_menu");
190         strcpy(mt->label, "Quick Favorites");
191         strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
192         mt->draw = screen_user_menu_draw;
193         WM_menutype_add(mt);
194 }
195
196 /** \} */