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