Tool System: per space/mode tool support
[blender.git] / source / blender / editors / space_topbar / space_topbar.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) 2017 Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/space_topbar/space_topbar.c
27  *  \ingroup sptopbar
28  */
29
30
31 #include <string.h>
32 #include <stdio.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BLI_blenlib.h"
37 #include "BLI_utildefines.h"
38
39 #include "BLO_readfile.h"
40 #include "BLT_translation.h"
41
42 #include "BKE_context.h"
43 #include "BKE_global.h"
44 #include "BKE_screen.h"
45
46 #include "ED_screen.h"
47 #include "ED_space_api.h"
48 #include "ED_undo.h"
49
50 #include "UI_interface.h"
51 #include "UI_resources.h"
52 #include "UI_view2d.h"
53
54 #include "RNA_access.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58 #include "WM_message.h"
59
60
61 void topbar_panels_register(ARegionType *art);
62
63 /* ******************** default callbacks for topbar space ***************** */
64
65 static SpaceLink *topbar_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
66 {
67         ARegion *ar;
68         SpaceTopBar *stopbar;
69
70         stopbar = MEM_callocN(sizeof(*stopbar), "init topbar");
71         stopbar->spacetype = SPACE_TOPBAR;
72
73         /* header */
74         ar = MEM_callocN(sizeof(ARegion), "left aligned header for topbar");
75         BLI_addtail(&stopbar->regionbase, ar);
76         ar->regiontype = RGN_TYPE_HEADER;
77         ar->alignment = RGN_ALIGN_TOP;
78         ar = MEM_callocN(sizeof(ARegion), "right aligned header for topbar");
79         BLI_addtail(&stopbar->regionbase, ar);
80         ar->regiontype = RGN_TYPE_HEADER;
81         ar->alignment = RGN_ALIGN_RIGHT | RGN_SPLIT_PREV;
82
83         /* main regions */
84         ar = MEM_callocN(sizeof(ARegion), "left aligned main region for topbar");
85         BLI_addtail(&stopbar->regionbase, ar);
86         ar->regiontype = RGN_TYPE_WINDOW;
87         ar->alignment = RGN_ALIGN_LEFT;
88         ar = MEM_callocN(sizeof(ARegion), "right aligned main region for topbar");
89         BLI_addtail(&stopbar->regionbase, ar);
90         ar->regiontype = RGN_TYPE_WINDOW;
91         ar->alignment = RGN_ALIGN_RIGHT;
92         ar = MEM_callocN(sizeof(ARegion), "center main region for topbar");
93         BLI_addtail(&stopbar->regionbase, ar);
94         ar->regiontype = RGN_TYPE_WINDOW;
95
96         return (SpaceLink *)stopbar;
97 }
98
99 /* not spacelink itself */
100 static void topbar_free(SpaceLink *UNUSED(sl))
101 {
102
103 }
104
105
106 /* spacetype; init callback */
107 static void topbar_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
108 {
109
110 }
111
112 static SpaceLink *topbar_duplicate(SpaceLink *sl)
113 {
114         SpaceTopBar *stopbarn = MEM_dupallocN(sl);
115
116         /* clear or remove stuff from old */
117
118         return (SpaceLink *)stopbarn;
119 }
120
121
122
123 /* add handlers, stuff you only do once or on area/region changes */
124 static void topbar_main_region_init(wmWindowManager *wm, ARegion *region)
125 {
126         wmKeyMap *keymap;
127
128         /* force delayed UI_view2d_region_reinit call */
129         if (ELEM(region->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
130                 region->flag |= RGN_FLAG_DYNAMIC_SIZE;
131         }
132         UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_HEADER, region->winx, region->winy);
133
134         keymap = WM_keymap_find(wm->defaultconf, "View2D Buttons List", 0, 0);
135         WM_event_add_keymap_handler(&region->handlers, keymap);
136 }
137
138 static void topbar_operatortypes(void)
139 {
140
141 }
142
143 static void topbar_keymap(struct wmKeyConfig *UNUSED(keyconf))
144 {
145
146 }
147
148 /* add handlers, stuff you only do once or on area/region changes */
149 static void topbar_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
150 {
151         if ((ar->alignment & ~RGN_SPLIT_PREV) == RGN_ALIGN_RIGHT) {
152                 ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
153         }
154         ED_region_header_init(ar);
155 }
156
157 static void topbar_main_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
158                                         wmNotifier *wmn, const Scene *UNUSED(scene))
159 {
160         /* context changes */
161         switch (wmn->category) {
162                 case NC_WM:
163                         if (wmn->data == ND_HISTORY)
164                                 ED_region_tag_redraw(ar);
165                         break;
166                 case NC_SCENE:
167                         if (wmn->data == ND_MODE)
168                                 ED_region_tag_redraw(ar);
169                         break;
170                 case NC_SPACE:
171                         if (wmn->data == ND_SPACE_VIEW3D)
172                                 ED_region_tag_redraw(ar);
173                         break;
174         }
175 }
176
177 static void topbar_header_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
178                                    wmNotifier *wmn, const Scene *UNUSED(scene))
179 {
180         /* context changes */
181         switch (wmn->category) {
182                 case NC_SCREEN:
183                         if (wmn->data == ND_LAYER)
184                                 ED_region_tag_redraw(ar);
185                         break;
186                 case NC_SCENE:
187                         if (wmn->data == ND_SCENEBROWSE)
188                                 ED_region_tag_redraw(ar);
189                         break;
190         }
191 }
192
193 static void topbar_header_region_message_subscribe(
194         const struct bContext *UNUSED(C),
195         struct WorkSpace *workspace, struct Scene *UNUSED(scene),
196         struct bScreen *UNUSED(screen), struct ScrArea *UNUSED(sa), struct ARegion *ar,
197         struct wmMsgBus *mbus)
198 {
199         wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
200                 .owner = ar,
201                 .user_data = ar,
202                 .notify = ED_region_do_msg_notify_tag_redraw,
203         };
204
205         WM_msg_subscribe_rna_prop(
206                 mbus, &workspace->id, workspace,
207                 WorkSpace, tools, &msg_sub_value_region_tag_redraw);
208 }
209
210 static void recent_files_menu_draw(const bContext *UNUSED(C), Menu *menu)
211 {
212         struct RecentFile *recent;
213         uiLayout *layout = menu->layout;
214         uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
215         if (!BLI_listbase_is_empty(&G.recent_files)) {
216                 for (recent = G.recent_files.first; (recent); recent = recent->next) {
217                         const char *file = BLI_path_basename(recent->filepath);
218                         const int icon = BLO_has_bfile_extension(file) ? ICON_FILE_BLEND : ICON_FILE_BACKUP;
219                         uiItemStringO(layout, file, icon, "WM_OT_open_mainfile", "filepath", recent->filepath);
220                 }
221         }
222         else {
223                 uiItemL(layout, IFACE_("No Recent Files"), ICON_NONE);
224         }
225 }
226
227 static void recent_files_menu_register(void)
228 {
229         MenuType *mt;
230
231         mt = MEM_callocN(sizeof(MenuType), "spacetype info menu recent files");
232         strcpy(mt->idname, "TOPBAR_MT_file_open_recent");
233         strcpy(mt->label, N_("Open Recent..."));
234         strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
235         mt->draw = recent_files_menu_draw;
236         WM_menutype_add(mt);
237 }
238
239
240 /* only called once, from space/spacetypes.c */
241 void ED_spacetype_topbar(void)
242 {
243         SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype topbar");
244         ARegionType *art;
245
246         st->spaceid = SPACE_TOPBAR;
247         strncpy(st->name, "Top Bar", BKE_ST_MAXNAME);
248
249         st->new = topbar_new;
250         st->free = topbar_free;
251         st->init = topbar_init;
252         st->duplicate = topbar_duplicate;
253         st->operatortypes = topbar_operatortypes;
254         st->keymap = topbar_keymap;
255
256         /* regions: main window */
257         art = MEM_callocN(sizeof(ARegionType), "spacetype topbar main region");
258         art->regionid = RGN_TYPE_WINDOW;
259         art->init = topbar_main_region_init;
260         art->layout = ED_region_header_layout;
261         art->draw = ED_region_header_draw;
262         art->listener = topbar_main_region_listener;
263         art->prefsizex = UI_UNIT_X * 5; /* Mainly to avoid glitches */
264         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
265
266         BLI_addhead(&st->regiontypes, art);
267
268         /* regions: header */
269         art = MEM_callocN(sizeof(ARegionType), "spacetype topbar header region");
270         art->regionid = RGN_TYPE_HEADER;
271         art->prefsizey = HEADERY;
272         art->prefsizex = UI_UNIT_X * 5; /* Mainly to avoid glitches */
273         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
274         art->listener = topbar_header_listener;
275         art->message_subscribe = topbar_header_region_message_subscribe;
276         art->init = topbar_header_region_init;
277         art->layout = ED_region_header_layout;
278         art->draw = ED_region_header_draw;
279
280         /* For popovers. */
281         topbar_panels_register(art);
282
283         BLI_addhead(&st->regiontypes, art);
284
285         recent_files_menu_register();
286
287         BKE_spacetype_register(st);
288 }
289
290
291 /* -------------------------------------------------------------------- */
292 /** \name Redo Panel
293  * \{ */
294
295 static int topbar_panel_operator_redo_poll(const bContext *C, PanelType *UNUSED(pt))
296 {
297         wmOperator *op = WM_operator_last_redo(C);
298         if (op == NULL) {
299                 return false;
300         }
301
302         bool success = false;
303         if (!WM_operator_check_ui_empty(op->type)) {
304                 const OperatorRepeatContextHandle *context_info;
305                 context_info = ED_operator_repeat_prepare_context((bContext *)C, op);
306                 success = WM_operator_poll((bContext *)C, op->type);
307                 ED_operator_repeat_reset_context((bContext *)C, context_info);
308         }
309         return success;
310 }
311
312 static void topbar_panel_operator_redo(const bContext *C, Panel *pa)
313 {
314         wmOperator *op = WM_operator_last_redo(C);
315         if (op == NULL) {
316                 return;
317         }
318         if (!WM_operator_check_ui_enabled(C, op->type->name)) {
319                 uiLayoutSetEnabled(pa->layout, false);
320         }
321         uiLayout *col = uiLayoutColumn(pa->layout, false);
322         uiTemplateOperatorRedoProperties(col, C);
323 }
324
325 void topbar_panels_register(ARegionType *art)
326 {
327         PanelType *pt;
328
329         pt = MEM_callocN(sizeof(PanelType), __func__);
330         strcpy(pt->idname, "TOPBAR_PT_redo");
331         strcpy(pt->label, N_("Redo"));
332         strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
333         pt->draw = topbar_panel_operator_redo;
334         pt->poll = topbar_panel_operator_redo_poll;
335         pt->space_type = SPACE_TOPBAR;
336         pt->region_type = RGN_TYPE_HEADER;
337         BLI_addtail(&art->paneltypes, pt);
338 }
339
340 /** \} */