svn merge -r39781:39792 https://svn.blender.org/svnroot/bf-blender/trunk/blender...
[blender-staging.git] / source / blender / editors / animation / anim_deps.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, Joshua Leung
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/animation/anim_deps.c
28  *  \ingroup edanimation
29  */
30
31
32 #include <string.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_anim_types.h"
37 #include "DNA_armature_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_node_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_sequence_types.h"
42
43 #include "BLI_blenlib.h"
44 #include "BLI_utildefines.h"
45
46 #include "BKE_animsys.h"
47 #include "BKE_action.h"
48 #include "BKE_context.h"
49 #include "BKE_depsgraph.h"
50 #include "BKE_global.h"
51 #include "BKE_node.h"
52 #include "BKE_sequencer.h"
53 #include "BKE_utildefines.h"
54
55 #include "RNA_access.h"
56
57 #include "ED_anim_api.h"
58
59 /* **************************** depsgraph tagging ******************************** */
60
61 /* tags the given anim list element for refreshes (if applicable)
62  * due to Animation Editor editing 
63  */
64 void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale)
65 {
66         ID *id;
67         FCurve *fcu;
68         AnimData *adt;
69
70         id= ale->id;
71         if (!id)
72                 return;
73         
74         /* tag AnimData for refresh so that other views will update in realtime with these changes */
75         adt= BKE_animdata_from_id(id);
76         if (adt)
77                 adt->recalc |= ADT_RECALC_ANIM;
78
79         /* update data */
80         fcu= (ale->datatype == ALE_FCURVE)? ale->key_data: NULL;
81                 
82         if (fcu && fcu->rna_path) {
83                 /* if we have an fcurve, call the update for the property we
84                    are editing, this is then expected to do the proper redraws
85                    and depsgraph updates  */
86                 PointerRNA id_ptr, ptr;
87                 PropertyRNA *prop;
88                 
89                 RNA_id_pointer_create(id, &id_ptr);
90                         
91                 if(RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop))
92                         RNA_property_update_main(G.main, scene, &ptr, prop);
93         }
94         else {
95                 /* in other case we do standard depsgaph update, ideally
96                    we'd be calling property update functions here too ... */
97                 DAG_id_tag_update(id, OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME); // XXX or do we want something more restrictive?
98         }
99 }
100
101 /* tags the given ID block for refreshes (if applicable) due to 
102  * Animation Editor editing */
103 void ANIM_id_update(Scene *UNUSED(scene), ID *id)
104 {
105         if (id) {
106                 AnimData *adt= BKE_animdata_from_id(id);
107                 
108                 /* tag AnimData for refresh so that other views will update in realtime with these changes */
109                 if (adt)
110                         adt->recalc |= ADT_RECALC_ANIM;
111                         
112                 /* set recalc flags */
113                 DAG_id_tag_update(id, OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME); // XXX or do we want something more restrictive?
114         }
115 }
116
117 /* **************************** animation data <-> data syncing ******************************** */
118 /* This code here is used to synchronise the 
119  *      - selection (to find selected data easier)
120  *      - ... (insert other relevant items here later) 
121  * status in relevant Blender data with the status stored in animation channels.
122  *
123  * This should be called in the refresh() callbacks for various editors in 
124  * response to appropriate notifiers.
125  */
126
127 /* perform syncing updates for Action Groups */
128 static void animchan_sync_group (bAnimContext *UNUSED(ac), bAnimListElem *ale)
129 {
130         bActionGroup *agrp= (bActionGroup *)ale->data;
131         ID *owner_id= ale->id;
132         
133         /* major priority is selection status
134          * so we need both a group and an owner
135          */
136         if (ELEM(NULL, agrp, owner_id))
137                 return;
138                 
139         /* for standard Objects, check if group is the name of some bone */
140         if (GS(owner_id->name) == ID_OB) {
141                 Object *ob= (Object *)owner_id;
142                 
143                 /* check if there are bones, and whether the name matches any 
144                  * NOTE: this feature will only really work if groups by default contain the F-Curves for a single bone
145                  */
146                 if (ob->pose) {
147                         bPoseChannel *pchan= get_pose_channel(ob->pose, agrp->name);
148                         
149                         /* if one matches, sync the selection status */
150                         if (pchan) {
151                                 if (pchan->bone->flag & BONE_SELECTED)
152                                         agrp->flag |= AGRP_SELECTED;
153                                 else
154                                         agrp->flag &= ~AGRP_SELECTED;
155                         }
156                 }
157         }
158 }
159  
160 /* perform syncing updates for F-Curves */
161 static void animchan_sync_fcurve (bAnimContext *UNUSED(ac), bAnimListElem *ale)
162 {
163         FCurve *fcu= (FCurve *)ale->data;
164         ID *owner_id= ale->id;
165         
166         /* major priority is selection status, so refer to the checks done in anim_filter.c 
167          * skip_fcurve_selected_data() for reference about what's going on here...
168          */
169         if (ELEM3(NULL, fcu, fcu->rna_path, owner_id))
170                 return;
171                 
172         if (GS(owner_id->name) == ID_OB) {
173                 Object *ob= (Object *)owner_id;
174                 
175                 /* only affect if F-Curve involves pose.bones */
176                 if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) {
177                         bPoseChannel *pchan;
178                         char *bone_name;
179                         
180                         /* get bone-name, and check if this bone is selected */
181                         bone_name= BLI_getQuotedStr(fcu->rna_path, "pose.bones[");
182                         pchan= get_pose_channel(ob->pose, bone_name);
183                         if (bone_name) MEM_freeN(bone_name);
184                         
185                         /* F-Curve selection depends on whether the bone is selected */
186                         if ((pchan) && (pchan->bone)) {
187                                 if (pchan->bone->flag & BONE_SELECTED)
188                                         fcu->flag |= FCURVE_SELECTED;
189                                 else
190                                         fcu->flag &= ~FCURVE_SELECTED;
191                         }
192                 }
193         }
194         else if (GS(owner_id->name) == ID_SCE) {
195                 Scene *scene = (Scene *)owner_id;
196                 
197                 /* only affect if F-Curve involves sequence_editor.sequences */
198                 if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
199                         Editing *ed= seq_give_editing(scene, FALSE);
200                         Sequence *seq;
201                         char *seq_name;
202                         
203                         /* get strip name, and check if this strip is selected */
204                         seq_name= BLI_getQuotedStr(fcu->rna_path, "sequences_all[");
205                         seq = get_seq_by_name(ed->seqbasep, seq_name, FALSE);
206                         if (seq_name) MEM_freeN(seq_name);
207                         
208                         /* can only add this F-Curve if it is selected */
209                         if (seq) {
210                                 if (seq->flag & SELECT)
211                                         fcu->flag |= FCURVE_SELECTED;
212                                 else
213                                         fcu->flag &= ~FCURVE_SELECTED;
214                         }
215                 }
216         }
217         else if (GS(owner_id->name) == ID_NT) {
218                 bNodeTree *ntree = (bNodeTree *)owner_id;
219                 
220                 /* check for selected nodes */
221                 if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) {
222                         bNode *node;
223                         char *node_name;
224                         
225                         /* get strip name, and check if this strip is selected */
226                         node_name= BLI_getQuotedStr(fcu->rna_path, "nodes[");
227                         node = nodeFindNodebyName(ntree, node_name);
228                         if (node_name) MEM_freeN(node_name);
229                         
230                         /* can only add this F-Curve if it is selected */
231                         if (node) {
232                                 if (node->flag & NODE_SELECT)
233                                         fcu->flag |= FCURVE_SELECTED;
234                                 else
235                                         fcu->flag &= ~FCURVE_SELECTED;
236                         }
237                 }
238         }
239 }
240
241 /* ---------------- */
242  
243 /* Main call to be exported to animation editors */
244 void ANIM_sync_animchannels_to_data (const bContext *C)
245 {
246         bAnimContext ac;
247         ListBase anim_data = {NULL, NULL};
248         bAnimListElem *ale;
249         int filter;
250         
251         /* get animation context info for filtering the channels */
252         // TODO: check on whether we need to set the area specially instead, since active area might not be ok?
253         if (ANIM_animdata_get_context(C, &ac) == 0)
254                 return;
255         
256         /* filter data */
257                 /* NOTE: we want all channels, since we want to be able to set selection status on some of them even when collapsed */
258         filter= ANIMFILTER_DATA_VISIBLE|ANIMFILTER_LIST_CHANNELS;
259         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
260         
261         /* flush settings as appropriate depending on the types of the channels */
262         for (ale= anim_data.first; ale; ale= ale->next) {
263                 switch (ale->type) {
264                         case ANIMTYPE_GROUP:
265                                 animchan_sync_group(&ac, ale);
266                                 break;
267                         
268                         case ANIMTYPE_FCURVE:
269                                 animchan_sync_fcurve(&ac, ale);
270                                 break;
271                 }
272         }
273         
274         BLI_freelistN(&anim_data);
275 }