Cleanup: style, use braces for editors
[blender.git] / source / blender / editors / animation / anim_deps.c
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) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edanimation
22  */
23
24 #include <string.h>
25
26 #include "MEM_guardedalloc.h"
27
28 #include "DNA_anim_types.h"
29 #include "DNA_armature_types.h"
30 #include "DNA_gpencil_types.h"
31 #include "DNA_object_types.h"
32 #include "DNA_node_types.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_sequence_types.h"
35
36 #include "BLI_blenlib.h"
37 #include "BLI_utildefines.h"
38
39 #include "BKE_animsys.h"
40 #include "BKE_action.h"
41 #include "BKE_context.h"
42 #include "BKE_fcurve.h"
43 #include "BKE_gpencil.h"
44 #include "BKE_main.h"
45 #include "BKE_node.h"
46 #include "BKE_sequencer.h"
47
48 #include "DEG_depsgraph.h"
49
50 #include "RNA_access.h"
51
52 #include "ED_anim_api.h"
53
54 /* **************************** depsgraph tagging ******************************** */
55
56 /* tags the given anim list element for refreshes (if applicable)
57  * due to Animation Editor editing
58  */
59 void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
60 {
61   ID *id;
62   FCurve *fcu;
63   AnimData *adt;
64
65   id = ale->id;
66   if (!id) {
67     return;
68   }
69
70   /* tag AnimData for refresh so that other views will update in realtime with these changes */
71   adt = BKE_animdata_from_id(id);
72   if (adt) {
73     DEG_id_tag_update(id, ID_RECALC_ANIMATION);
74     if (adt->action != NULL) {
75       DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION);
76     }
77   }
78
79   /* Tag copy on the main object if updating anything directly inside AnimData */
80   if (ELEM(ale->type,
81            ANIMTYPE_ANIMDATA,
82            ANIMTYPE_NLAACTION,
83            ANIMTYPE_NLATRACK,
84            ANIMTYPE_NLACURVE)) {
85     DEG_id_tag_update(id, ID_RECALC_ANIMATION);
86     return;
87   }
88
89   /* update data */
90   fcu = (ale->datatype == ALE_FCURVE) ? ale->key_data : NULL;
91
92   if (fcu && fcu->rna_path) {
93     /* if we have an fcurve, call the update for the property we
94      * are editing, this is then expected to do the proper redraws
95      * and depsgraph updates  */
96     PointerRNA id_ptr, ptr;
97     PropertyRNA *prop;
98
99     RNA_id_pointer_create(id, &id_ptr);
100
101     if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
102       RNA_property_update_main(bmain, scene, &ptr, prop);
103     }
104   }
105   else {
106     /* in other case we do standard depsgraph update, ideally
107      * we'd be calling property update functions here too ... */
108     DEG_id_tag_update(id,
109                       ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY |
110                           ID_RECALC_ANIMATION);  // XXX or do we want something more restrictive?
111   }
112 }
113
114 /* tags the given ID block for refreshes (if applicable) due to
115  * Animation Editor editing */
116 void ANIM_id_update(Main *bmain, ID *id)
117 {
118   if (id) {
119     DEG_id_tag_update_ex(
120         bmain,
121         id,
122         ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY |
123             ID_RECALC_ANIMATION);  // XXX or do we want something more restrictive?
124   }
125 }
126
127 /* **************************** animation data <-> data syncing ******************************** */
128 /* This code here is used to synchronize the
129  * - selection (to find selected data easier)
130  * - ... (insert other relevant items here later)
131  * status in relevant Blender data with the status stored in animation channels.
132  *
133  * This should be called in the refresh() callbacks for various editors in
134  * response to appropriate notifiers.
135  */
136
137 /* perform syncing updates for Action Groups */
138 static void animchan_sync_group(bAnimContext *ac, bAnimListElem *ale, bActionGroup **active_agrp)
139 {
140   bActionGroup *agrp = (bActionGroup *)ale->data;
141   ID *owner_id = ale->id;
142
143   /* major priority is selection status
144    * so we need both a group and an owner
145    */
146   if (ELEM(NULL, agrp, owner_id)) {
147     return;
148   }
149
150   /* for standard Objects, check if group is the name of some bone */
151   if (GS(owner_id->name) == ID_OB) {
152     Object *ob = (Object *)owner_id;
153
154     /* check if there are bones, and whether the name matches any
155      * NOTE: this feature will only really work if groups by default contain the F-Curves
156      * for a single bone.
157      */
158     if (ob->pose) {
159       bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name);
160       bArmature *arm = ob->data;
161
162       if (pchan) {
163         bActionGroup *bgrp;
164
165         /* if one matches, sync the selection status */
166         if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
167           agrp->flag |= AGRP_SELECTED;
168         }
169         else {
170           agrp->flag &= ~AGRP_SELECTED;
171         }
172
173         /* also sync active group status */
174         if ((ob == ac->obact) && (pchan->bone == arm->act_bone)) {
175           /* if no previous F-Curve has active flag, then we're the first and only one to get it */
176           if (*active_agrp == NULL) {
177             agrp->flag |= AGRP_ACTIVE;
178             *active_agrp = agrp;
179           }
180           else {
181             /* someone else has already taken it - set as not active */
182             agrp->flag &= ~AGRP_ACTIVE;
183           }
184         }
185         else {
186           /* this can't possibly be active now */
187           agrp->flag &= ~AGRP_ACTIVE;
188         }
189
190         /* sync group colors */
191         bgrp = (bActionGroup *)BLI_findlink(&ob->pose->agroups, (pchan->agrp_index - 1));
192         if (bgrp) {
193           agrp->customCol = bgrp->customCol;
194           action_group_colors_sync(agrp, bgrp);
195         }
196       }
197     }
198   }
199 }
200
201 /* perform syncing updates for F-Curves */
202 static void animchan_sync_fcurve(bAnimContext *UNUSED(ac),
203                                  bAnimListElem *ale,
204                                  FCurve **active_fcurve)
205 {
206   FCurve *fcu = (FCurve *)ale->data;
207   ID *owner_id = ale->id;
208
209   /* major priority is selection status, so refer to the checks done in anim_filter.c
210    * skip_fcurve_selected_data() for reference about what's going on here...
211    */
212   if (ELEM(NULL, fcu, fcu->rna_path, owner_id)) {
213     return;
214   }
215
216   if (GS(owner_id->name) == ID_SCE) {
217     Scene *scene = (Scene *)owner_id;
218
219     /* only affect if F-Curve involves sequence_editor.sequences */
220     if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
221       Editing *ed = BKE_sequencer_editing_get(scene, false);
222       Sequence *seq;
223       char *seq_name;
224
225       /* get strip name, and check if this strip is selected */
226       seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all[");
227       seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, false);
228       if (seq_name) {
229         MEM_freeN(seq_name);
230       }
231
232       /* update selection status */
233       if (seq) {
234         if (seq->flag & SELECT) {
235           fcu->flag |= FCURVE_SELECTED;
236         }
237         else {
238           fcu->flag &= ~FCURVE_SELECTED;
239         }
240       }
241     }
242   }
243   else if (GS(owner_id->name) == ID_NT) {
244     bNodeTree *ntree = (bNodeTree *)owner_id;
245
246     /* check for selected nodes */
247     if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) {
248       bNode *node;
249       char *node_name;
250
251       /* get strip name, and check if this strip is selected */
252       node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes[");
253       node = nodeFindNodebyName(ntree, node_name);
254       if (node_name) {
255         MEM_freeN(node_name);
256       }
257
258       /* update selection/active status */
259       if (node) {
260         /* update selection status */
261         if (node->flag & NODE_SELECT) {
262           fcu->flag |= FCURVE_SELECTED;
263         }
264         else {
265           fcu->flag &= ~FCURVE_SELECTED;
266         }
267
268         /* update active status */
269         /* XXX: this may interfere with setting bones as active if both exist at once;
270          * then again, if that's the case, production setups aren't likely to be animating
271          * nodes while working with bones?
272          */
273         if (node->flag & NODE_ACTIVE) {
274           if (*active_fcurve == NULL) {
275             fcu->flag |= FCURVE_ACTIVE;
276             *active_fcurve = fcu;
277           }
278           else {
279             fcu->flag &= ~FCURVE_ACTIVE;
280           }
281         }
282         else {
283           fcu->flag &= ~FCURVE_ACTIVE;
284         }
285       }
286     }
287   }
288 }
289
290 /* perform syncing updates for GPencil Layers */
291 static void animchan_sync_gplayer(bAnimContext *UNUSED(ac), bAnimListElem *ale)
292 {
293   bGPDlayer *gpl = (bGPDlayer *)ale->data;
294
295   /* Make sure the selection flags agree with the "active" flag.
296    * The selection flags are used in the Dopesheet only, whereas
297    * the active flag is used everywhere else. Hence, we try to
298    * sync these here so that it all seems to be have as the user
299    * expects - T50184
300    *
301    * Assume that we only really do this when the active status changes.
302    * (NOTE: This may prove annoying if it means selection is always lost)
303    */
304   if (gpl->flag & GP_LAYER_ACTIVE) {
305     gpl->flag |= GP_LAYER_SELECT;
306   }
307   else {
308     gpl->flag &= ~GP_LAYER_SELECT;
309   }
310 }
311
312 /* ---------------- */
313
314 /* Main call to be exported to animation editors */
315 void ANIM_sync_animchannels_to_data(const bContext *C)
316 {
317   bAnimContext ac;
318   ListBase anim_data = {NULL, NULL};
319   bAnimListElem *ale;
320   int filter;
321
322   bActionGroup *active_agrp = NULL;
323   FCurve *active_fcurve = NULL;
324
325   /* get animation context info for filtering the channels */
326   if (ANIM_animdata_get_context(C, &ac) == 0) {
327     return;
328   }
329
330   /* filter data */
331
332   /* NOTE: we want all channels, since we want to be able to set selection status on some of them
333    * even when collapsed... however,
334    * don't include duplicates so that selection statuses don't override each other.
335    */
336   filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS;
337   ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
338
339   /* flush settings as appropriate depending on the types of the channels */
340   for (ale = anim_data.first; ale; ale = ale->next) {
341     switch (ale->type) {
342       case ANIMTYPE_GROUP:
343         animchan_sync_group(&ac, ale, &active_agrp);
344         break;
345
346       case ANIMTYPE_FCURVE:
347         animchan_sync_fcurve(&ac, ale, &active_fcurve);
348         break;
349
350       case ANIMTYPE_GPLAYER:
351         animchan_sync_gplayer(&ac, ale);
352         break;
353     }
354   }
355
356   ANIM_animdata_freelist(&anim_data);
357 }
358
359 void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
360 {
361   bAnimListElem *ale;
362
363   if (ELEM(ac->datatype, ANIMCONT_MASK)) {
364 #ifdef DEBUG
365     /* quiet assert */
366     for (ale = anim_data->first; ale; ale = ale->next) {
367       ale->update = 0;
368     }
369 #endif
370     return;
371   }
372
373   for (ale = anim_data->first; ale; ale = ale->next) {
374     if (ale->type == ANIMTYPE_GPLAYER) {
375       bGPDlayer *gpl = ale->data;
376
377       if (ale->update & ANIM_UPDATE_ORDER) {
378         ale->update &= ~ANIM_UPDATE_ORDER;
379         if (gpl) {
380           //gpencil_sort_frames(gpl);
381         }
382       }
383
384       if (ale->update & ANIM_UPDATE_DEPS) {
385         ale->update &= ~ANIM_UPDATE_DEPS;
386         ANIM_list_elem_update(ac->bmain, ac->scene, ale);
387       }
388       /* disable handles to avoid crash */
389       if (ale->update & ANIM_UPDATE_HANDLES) {
390         ale->update &= ~ANIM_UPDATE_HANDLES;
391       }
392     }
393     else if (ale->datatype == ALE_FCURVE) {
394       FCurve *fcu = ale->key_data;
395
396       if (ale->update & ANIM_UPDATE_ORDER) {
397         ale->update &= ~ANIM_UPDATE_ORDER;
398         if (fcu) {
399           sort_time_fcurve(fcu);
400         }
401       }
402
403       if (ale->update & ANIM_UPDATE_HANDLES) {
404         ale->update &= ~ANIM_UPDATE_HANDLES;
405         if (fcu) {
406           calchandles_fcurve(fcu);
407         }
408       }
409
410       if (ale->update & ANIM_UPDATE_DEPS) {
411         ale->update &= ~ANIM_UPDATE_DEPS;
412         ANIM_list_elem_update(ac->bmain, ac->scene, ale);
413       }
414     }
415     else if (ELEM(ale->type,
416                   ANIMTYPE_ANIMDATA,
417                   ANIMTYPE_NLAACTION,
418                   ANIMTYPE_NLATRACK,
419                   ANIMTYPE_NLACURVE)) {
420       if (ale->update & ANIM_UPDATE_DEPS) {
421         ale->update &= ~ANIM_UPDATE_DEPS;
422         ANIM_list_elem_update(ac->bmain, ac->scene, ale);
423       }
424     }
425     else if (ale->update) {
426 #if 0
427       if (G.debug & G_DEBUG) {
428         printf("%s: Unhandled animchannel updates (%d) for type=%d (%p)\n",
429                __func__,
430                ale->update,
431                ale->type,
432                ale->data);
433       }
434 #endif
435       /* Prevent crashes in cases where it can't be handled */
436       ale->update = 0;
437     }
438
439     BLI_assert(ale->update == 0);
440   }
441 }
442
443 void ANIM_animdata_freelist(ListBase *anim_data)
444 {
445 #ifndef NDEBUG
446   bAnimListElem *ale, *ale_next;
447   for (ale = anim_data->first; ale; ale = ale_next) {
448     ale_next = ale->next;
449     BLI_assert(ale->update == 0);
450     MEM_freeN(ale);
451   }
452   BLI_listbase_clear(anim_data);
453 #else
454   BLI_freelistN(anim_data);
455 #endif
456 }