Workbench: Cleaner Shadow edges own shadow
[blender.git] / source / blender / editors / space_buttons / space_buttons.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) 2008 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/space_buttons/space_buttons.c
28  *  \ingroup spbuttons
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 "BKE_context.h"
40 #include "BKE_screen.h"
41
42 #include "ED_space_api.h"
43 #include "ED_screen.h"
44
45 #include "WM_api.h"
46 #include "WM_types.h"
47 #include "WM_message.h"
48
49 #include "RNA_access.h"
50
51 #include "buttons_intern.h"  /* own include */
52
53 /* ******************** default callbacks for buttons space ***************** */
54
55 static SpaceLink *buttons_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
56 {
57         ARegion *ar;
58         SpaceButs *sbuts;
59         
60         sbuts = MEM_callocN(sizeof(SpaceButs), "initbuts");
61         sbuts->spacetype = SPACE_BUTS;
62         sbuts->align = BUT_VERTICAL;
63
64         /* header */
65         ar = MEM_callocN(sizeof(ARegion), "header for buts");
66         
67         BLI_addtail(&sbuts->regionbase, ar);
68         ar->regiontype = RGN_TYPE_HEADER;
69         ar->alignment = RGN_ALIGN_TOP;
70         
71 #if 0
72         /* context region */
73         ar = MEM_callocN(sizeof(ARegion), "context region for buts");
74         BLI_addtail(&sbuts->regionbase, ar);
75         ar->regiontype = RGN_TYPE_CHANNELS;
76         ar->alignment = RGN_ALIGN_TOP;
77 #endif
78
79         /* main region */
80         ar = MEM_callocN(sizeof(ARegion), "main region for buts");
81         
82         BLI_addtail(&sbuts->regionbase, ar);
83         ar->regiontype = RGN_TYPE_WINDOW;
84
85         return (SpaceLink *)sbuts;
86 }
87
88 /* not spacelink itself */
89 static void buttons_free(SpaceLink *sl)
90 {       
91         SpaceButs *sbuts = (SpaceButs *) sl;
92
93         if (sbuts->path)
94                 MEM_freeN(sbuts->path);
95         
96         if (sbuts->texuser) {
97                 ButsContextTexture *ct = sbuts->texuser;
98                 BLI_freelistN(&ct->users);
99                 MEM_freeN(ct);
100         }
101 }
102
103 /* spacetype; init callback */
104 static void buttons_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa)
105 {
106         SpaceButs *sbuts = sa->spacedata.first;
107
108         /* auto-align based on size */
109         if (sbuts->align == BUT_AUTO || !sbuts->align) {
110                 if (sa->winx > sa->winy)
111                         sbuts->align = BUT_HORIZONTAL;
112                 else
113                         sbuts->align = BUT_VERTICAL;
114         }
115 }
116
117 static SpaceLink *buttons_duplicate(SpaceLink *sl)
118 {
119         SpaceButs *sbutsn = MEM_dupallocN(sl);
120         
121         /* clear or remove stuff from old */
122         sbutsn->path = NULL;
123         sbutsn->texuser = NULL;
124         
125         return (SpaceLink *)sbutsn;
126 }
127
128 /* add handlers, stuff you only do once or on area/region changes */
129 static void buttons_main_region_init(wmWindowManager *wm, ARegion *ar)
130 {
131         wmKeyMap *keymap;
132
133         ED_region_panels_init(wm, ar);
134
135         keymap = WM_keymap_find(wm->defaultconf, "Property Editor", SPACE_BUTS, 0);
136         WM_event_add_keymap_handler(&ar->handlers, keymap);
137 }
138
139 static void buttons_main_region_draw(const bContext *C, ARegion *ar)
140 {
141         /* draw entirely, view changes should be handled here */
142         SpaceButs *sbuts = CTX_wm_space_buts(C);
143         const bool vertical = (sbuts->align == BUT_VERTICAL);
144
145         buttons_context_compute(C, sbuts);
146
147         if (sbuts->mainb == BCONTEXT_SCENE)
148                 ED_region_panels(C, ar, "scene", sbuts->mainb, vertical);
149         else if (sbuts->mainb == BCONTEXT_RENDER)
150                 ED_region_panels(C, ar, "render", sbuts->mainb, vertical);
151         else if (sbuts->mainb == BCONTEXT_VIEW_LAYER)
152                 ED_region_panels(C, ar, "view_layer", sbuts->mainb, vertical);
153         else if (sbuts->mainb == BCONTEXT_WORLD)
154                 ED_region_panels(C, ar, "world", sbuts->mainb, vertical);
155         else if (sbuts->mainb == BCONTEXT_WORKSPACE)
156                 ED_region_panels(C, ar, "workspace", sbuts->mainb, vertical);
157         else if (sbuts->mainb == BCONTEXT_COLLECTION)
158                 ED_region_panels(C, ar, "collection", sbuts->mainb, vertical);
159         else if (sbuts->mainb == BCONTEXT_OBJECT)
160                 ED_region_panels(C, ar, "object", sbuts->mainb, vertical);
161         else if (sbuts->mainb == BCONTEXT_DATA)
162                 ED_region_panels(C, ar, "data", sbuts->mainb, vertical);
163         else if (sbuts->mainb == BCONTEXT_MATERIAL)
164                 ED_region_panels(C, ar, "material", sbuts->mainb, vertical);
165         else if (sbuts->mainb == BCONTEXT_TEXTURE)
166                 ED_region_panels(C, ar, "texture", sbuts->mainb, vertical);
167         else if (sbuts->mainb == BCONTEXT_PARTICLE)
168                 ED_region_panels(C, ar, "particle", sbuts->mainb, vertical);
169         else if (sbuts->mainb == BCONTEXT_PHYSICS)
170                 ED_region_panels(C, ar, "physics", sbuts->mainb, vertical);
171         else if (sbuts->mainb == BCONTEXT_BONE)
172                 ED_region_panels(C, ar, "bone", sbuts->mainb, vertical);
173         else if (sbuts->mainb == BCONTEXT_MODIFIER)
174                 ED_region_panels(C, ar, "modifier", sbuts->mainb, vertical);
175         else if (sbuts->mainb == BCONTEXT_CONSTRAINT)
176                 ED_region_panels(C, ar, "constraint", sbuts->mainb, vertical);
177         else if (sbuts->mainb == BCONTEXT_BONE_CONSTRAINT)
178                 ED_region_panels(C, ar, "bone_constraint", sbuts->mainb, vertical);
179
180         sbuts->re_align = 0;
181         sbuts->mainbo = sbuts->mainb;
182 }
183
184 static void buttons_main_region_listener(
185         bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn,
186         const Scene *UNUSED(scene))
187 {
188         /* context changes */
189         switch (wmn->category) {
190                 case NC_SCREEN:
191                         if (ELEM(wmn->data, ND_LAYER)) {
192                                 ED_region_tag_redraw(ar);
193                         }
194                         break;
195         }
196 }
197
198 static void buttons_operatortypes(void)
199 {
200         WM_operatortype_append(BUTTONS_OT_toolbox);
201         WM_operatortype_append(BUTTONS_OT_file_browse);
202         WM_operatortype_append(BUTTONS_OT_directory_browse);
203 }
204
205 static void buttons_keymap(struct wmKeyConfig *keyconf)
206 {
207         wmKeyMap *keymap = WM_keymap_find(keyconf, "Property Editor", SPACE_BUTS, 0);
208         
209         WM_keymap_add_item(keymap, "BUTTONS_OT_toolbox", RIGHTMOUSE, KM_PRESS, 0, 0);
210 }
211
212 /* add handlers, stuff you only do once or on area/region changes */
213 static void buttons_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar)
214 {
215         ED_region_header_init(ar);
216 }
217
218 static void buttons_header_region_draw(const bContext *C, ARegion *ar)
219 {
220         SpaceButs *sbuts = CTX_wm_space_buts(C);
221
222         /* Needed for RNA to get the good values! */
223         buttons_context_compute(C, sbuts);
224
225         ED_region_header(C, ar);
226 }
227
228 static void buttons_header_region_message_subscribe(
229         const bContext *UNUSED(C),
230         WorkSpace *UNUSED(workspace), Scene *UNUSED(scene),
231         bScreen *UNUSED(screen), ScrArea *sa, ARegion *ar,
232         struct wmMsgBus *mbus)
233 {
234         SpaceButs *sbuts = sa->spacedata.first;
235         wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
236                 .owner = ar,
237                 .user_data = ar,
238                 .notify = ED_region_do_msg_notify_tag_redraw,
239         };
240
241         /* Don't check for SpaceButs.mainb here, we may toggle between view-layers
242          * where one has no active object, so that available contexts changes. */
243         WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw);
244
245         if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_WORLD)) {
246                 WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
247         }
248 }
249
250 /* draw a certain button set only if properties area is currently
251  * showing that button set, to reduce unnecessary drawing. */
252 static void buttons_area_redraw(ScrArea *sa, short buttons)
253 {
254         SpaceButs *sbuts = sa->spacedata.first;
255         
256         /* if the area's current button set is equal to the one to redraw */
257         if (sbuts->mainb == buttons)
258                 ED_area_tag_redraw(sa);
259 }
260
261 /* reused! */
262 static void buttons_area_listener(
263         bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene),
264         WorkSpace *UNUSED(workspace))
265 {
266         SpaceButs *sbuts = sa->spacedata.first;
267
268         /* context changes */
269         switch (wmn->category) {
270                 case NC_SCENE:
271                         switch (wmn->data) {
272                                 case ND_RENDER_OPTIONS:
273                                         buttons_area_redraw(sa, BCONTEXT_RENDER);
274                                         buttons_area_redraw(sa, BCONTEXT_VIEW_LAYER);
275                                         break;
276                                 case ND_WORLD:
277                                         buttons_area_redraw(sa, BCONTEXT_WORLD);
278                                         sbuts->preview = 1;
279                                         break;
280                                 case ND_FRAME:
281                                         /* any buttons area can have animated properties so redraw all */
282                                         ED_area_tag_redraw(sa);
283                                         sbuts->preview = 1;
284                                         break;
285                                 case ND_OB_ACTIVE:
286                                         ED_area_tag_redraw(sa);
287                                         sbuts->preview = 1;
288                                         break;
289                                 case ND_KEYINGSET:
290                                         buttons_area_redraw(sa, BCONTEXT_SCENE);
291                                         break;
292                                 case ND_RENDER_RESULT:
293                                         break;
294                                 case ND_MODE:
295                                 case ND_LAYER:
296                                 default:
297                                         ED_area_tag_redraw(sa);
298                                         break;
299                         }
300                         break;
301                 case NC_OBJECT:
302                         switch (wmn->data) {
303                                 case ND_TRANSFORM:
304                                         buttons_area_redraw(sa, BCONTEXT_OBJECT);
305                                         buttons_area_redraw(sa, BCONTEXT_DATA); /* autotexpace flag */
306                                         break;
307                                 case ND_POSE:
308                                         buttons_area_redraw(sa, BCONTEXT_DATA);
309                                         break;
310                                 case ND_BONE_ACTIVE:
311                                 case ND_BONE_SELECT:
312                                         buttons_area_redraw(sa, BCONTEXT_BONE);
313                                         buttons_area_redraw(sa, BCONTEXT_BONE_CONSTRAINT);
314                                         buttons_area_redraw(sa, BCONTEXT_DATA);
315                                         break;
316                                 case ND_MODIFIER:
317                                         if (wmn->action == NA_RENAME)
318                                                 ED_area_tag_redraw(sa);
319                                         else
320                                                 buttons_area_redraw(sa, BCONTEXT_MODIFIER);
321                                         buttons_area_redraw(sa, BCONTEXT_PHYSICS);
322                                         break;
323                                 case ND_CONSTRAINT:
324                                         buttons_area_redraw(sa, BCONTEXT_CONSTRAINT);
325                                         buttons_area_redraw(sa, BCONTEXT_BONE_CONSTRAINT);
326                                         break;
327                                 case ND_PARTICLE:
328                                         if (wmn->action == NA_EDITED)
329                                                 buttons_area_redraw(sa, BCONTEXT_PARTICLE);
330                                         sbuts->preview = 1;
331                                         break;
332                                 case ND_DRAW:
333                                         buttons_area_redraw(sa, BCONTEXT_OBJECT);
334                                         buttons_area_redraw(sa, BCONTEXT_DATA);
335                                         buttons_area_redraw(sa, BCONTEXT_PHYSICS);
336                                         break;
337                                 case ND_SHADING:
338                                 case ND_SHADING_DRAW:
339                                 case ND_SHADING_LINKS:
340                                 case ND_SHADING_PREVIEW:
341                                         /* currently works by redraws... if preview is set, it (re)starts job */
342                                         sbuts->preview = 1;
343                                         break;
344                                 default:
345                                         /* Not all object RNA props have a ND_ notifier (yet) */
346                                         ED_area_tag_redraw(sa);
347                                         break;
348                         }
349                         break;
350                 case NC_GEOM:
351                         switch (wmn->data) {
352                                 case ND_SELECT:
353                                 case ND_DATA:
354                                 case ND_VERTEX_GROUP:
355                                         ED_area_tag_redraw(sa);
356                                         break;
357                         }
358                         break;
359                 case NC_MATERIAL:
360                         ED_area_tag_redraw(sa);
361                         switch (wmn->data) {
362                                 case ND_SHADING:
363                                 case ND_SHADING_DRAW:
364                                 case ND_SHADING_LINKS:
365                                 case ND_SHADING_PREVIEW:
366                                 case ND_NODES:
367                                         /* currently works by redraws... if preview is set, it (re)starts job */
368                                         sbuts->preview = 1;
369                                         break;
370                         }
371                         break;
372                 case NC_WORLD:
373                         buttons_area_redraw(sa, BCONTEXT_WORLD);
374                         sbuts->preview = 1;
375                         break;
376                 case NC_LAMP:
377                         buttons_area_redraw(sa, BCONTEXT_DATA);
378                         sbuts->preview = 1;
379                         break;
380                 case NC_GROUP:
381                         buttons_area_redraw(sa, BCONTEXT_OBJECT);
382                         break;
383                 case NC_BRUSH:
384                         buttons_area_redraw(sa, BCONTEXT_TEXTURE);
385                         sbuts->preview = 1;
386                         break;
387                 case NC_TEXTURE:
388                 case NC_IMAGE:
389                         if (wmn->action != NA_PAINTING) {
390                                 ED_area_tag_redraw(sa);
391                                 sbuts->preview = 1;
392                         }
393                         break;
394                 case NC_SPACE:
395                         if (wmn->data == ND_SPACE_PROPERTIES)
396                                 ED_area_tag_redraw(sa);
397                         break;
398                 case NC_ID:
399                         if (wmn->action == NA_RENAME)
400                                 ED_area_tag_redraw(sa);
401                         break;
402                 case NC_ANIMATION:
403                         switch (wmn->data) {
404                                 case ND_KEYFRAME:
405                                         if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED))
406                                                 ED_area_tag_redraw(sa);
407                                         break;
408                         }
409                         break;
410                 case NC_NODE:
411                         if (wmn->action == NA_SELECTED) {
412                                 ED_area_tag_redraw(sa);
413                                 /* new active node, update texture preview */
414                                 if (sbuts->mainb == BCONTEXT_TEXTURE)
415                                         sbuts->preview = 1;
416                         }
417                         break;
418                 /* Listener for preview render, when doing an global undo. */
419                 case NC_WM:
420                         if (wmn->data == ND_UNDO) {
421                                 ED_area_tag_redraw(sa);
422                                 sbuts->preview = 1;
423                         }
424                         break;
425 #ifdef WITH_FREESTYLE
426                 case NC_LINESTYLE:
427                         ED_area_tag_redraw(sa);
428                         sbuts->preview = 1;
429                         break;
430 #endif
431         }
432
433         if (wmn->data == ND_KEYS)
434                 ED_area_tag_redraw(sa);
435 }
436
437 static void buttons_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
438 {
439         SpaceButs *sbuts = (SpaceButs *)slink;
440
441         if (sbuts->pinid == old_id) {
442                 sbuts->pinid = new_id;
443                 if (new_id == NULL) {
444                         sbuts->flag &= ~SB_PIN_CONTEXT;
445                 }
446         }
447
448         if (sbuts->path) {
449                 ButsContextPath *path = sbuts->path;
450                 int i;
451
452                 for (i = 0; i < path->len; i++) {
453                         if (path->ptr[i].id.data == old_id) {
454                                 break;
455                         }
456                 }
457
458                 if (i == path->len) {
459                         /* pass */
460                 }
461                 else if (new_id == NULL) {
462                         if (i == 0) {
463                                 MEM_SAFE_FREE(sbuts->path);
464                         }
465                         else {
466                                 memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
467                                 path->len = i;
468                         }
469                 }
470                 else {
471                         RNA_id_pointer_create(new_id, &path->ptr[i]);
472                         /* There is no easy way to check/make path downwards valid, just nullify it.
473                          * Next redraw will rebuild this anyway. */
474                         i++;
475                         memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));
476                         path->len = i;
477                 }
478         }
479
480         if (sbuts->texuser) {
481                 ButsContextTexture *ct = sbuts->texuser;
482                 if ((ID *)ct->texture == old_id) {
483                         ct->texture = (Tex *)new_id;
484                 }
485                 BLI_freelistN(&ct->users);
486                 ct->user = NULL;
487         }
488 }
489
490 /* only called once, from space/spacetypes.c */
491 void ED_spacetype_buttons(void)
492 {
493         SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype buttons");
494         ARegionType *art;
495         
496         st->spaceid = SPACE_BUTS;
497         strncpy(st->name, "Buttons", BKE_ST_MAXNAME);
498         
499         st->new = buttons_new;
500         st->free = buttons_free;
501         st->init = buttons_init;
502         st->duplicate = buttons_duplicate;
503         st->operatortypes = buttons_operatortypes;
504         st->keymap = buttons_keymap;
505         st->listener = buttons_area_listener;
506         st->context = buttons_context;
507         st->id_remap = buttons_id_remap;
508
509         /* regions: main window */
510         art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region");
511         art->regionid = RGN_TYPE_WINDOW;
512         art->init = buttons_main_region_init;
513         art->draw = buttons_main_region_draw;
514         art->listener = buttons_main_region_listener;
515         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
516         BLI_addhead(&st->regiontypes, art);
517
518         buttons_context_register(art);
519         
520         /* regions: header */
521         art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region");
522         art->regionid = RGN_TYPE_HEADER;
523         art->prefsizey = HEADERY;
524         art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
525         
526         art->init = buttons_header_region_init;
527         art->draw = buttons_header_region_draw;
528         art->message_subscribe = buttons_header_region_message_subscribe;
529         BLI_addhead(&st->regiontypes, art);
530
531         BKE_spacetype_register(st);
532 }
533