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