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