Merge with trunk r37757.
[blender.git] / source / blender / editors / space_graph / graph_utils.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) 2009 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/space_graph/graph_utils.c
30  *  \ingroup spgraph
31  */
32
33
34 #include <string.h>
35 #include <stdio.h>
36 #include <math.h>
37 #include <float.h>
38
39 #include "DNA_anim_types.h"
40 #include "DNA_space_types.h"
41 #include "DNA_screen_types.h"
42
43 #include "MEM_guardedalloc.h"
44
45 #include "BLI_math.h"
46 #include "BLI_blenlib.h"
47 #include "BLI_editVert.h"
48 #include "BLI_rand.h"
49
50 #include "BKE_context.h"
51 #include "BKE_fcurve.h"
52
53
54 #include "WM_api.h"
55
56
57 #include "ED_anim_api.h"
58
59
60 #include "graph_intern.h"       // own include
61
62 /* ************************************************************** */
63 /* Active F-Curve */
64
65 /* Find 'active' F-Curve. It must be editable, since that's the purpose of these buttons (subject to change).  
66  * We return the 'wrapper' since it contains valuable context info (about hierarchy), which will need to be freed 
67  * when the caller is done with it.
68  *
69  * NOTE: curve-visible flag isn't included, otherwise selecting a curve via list to edit is too cumbersome
70  */
71 bAnimListElem *get_active_fcurve_channel (bAnimContext *ac)
72 {
73         ListBase anim_data = {NULL, NULL};
74         int filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_ACTIVE);
75         size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
76         
77         /* We take the first F-Curve only, since some other ones may have had 'active' flag set
78          * if they were from linked data.
79          */
80         if (items) {
81                 bAnimListElem *ale= (bAnimListElem *)anim_data.first;
82                 
83                 /* remove first item from list, then free the rest of the list and return the stored one */
84                 BLI_remlink(&anim_data, ale);
85                 BLI_freelistN(&anim_data);
86                 
87                 return ale;
88         }
89         
90         /* no active F-Curve */
91         return NULL;
92 }
93
94 /* ************************************************************** */
95 /* Operator Polling Callbacks */
96
97 /* Check if there are any visible keyframes (for selection tools) */
98 int graphop_visible_keyframes_poll (bContext *C)
99 {
100         bAnimContext ac;
101         bAnimListElem *ale;
102         ListBase anim_data = {NULL, NULL};
103         ScrArea *sa= CTX_wm_area(C);
104         size_t items;
105         int filter;
106         short found = 0;
107         
108         /* firstly, check if in Graph Editor */
109         // TODO: also check for region?
110         if ((sa == NULL) || (sa->spacetype != SPACE_IPO))
111                 return 0;
112                 
113         /* try to init Anim-Context stuff ourselves and check */
114         if (ANIM_animdata_get_context(C, &ac) == 0)
115                 return 0;
116         
117         /* loop over the visible (selection doesn't matter) F-Curves, and see if they're suitable
118          * stopping on the first successful match
119          */
120         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE);
121         items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
122         if (items == 0) 
123                 return 0;
124         
125         for (ale = anim_data.first; ale; ale= ale->next) {
126                 FCurve *fcu= (FCurve *)ale->data;
127                 
128                 /* visible curves for selection must fulfull the following criteria:
129                  *      - it has bezier keyframes
130                  *      - F-Curve modifiers do not interfere with the result too much 
131                  *        (i.e. the modifier-control drawing check returns false)
132                  */
133                 if (fcu->bezt == NULL)
134                         continue;
135                 if (fcurve_are_keyframes_usable(fcu)) {
136                         found = 1;
137                         break;
138                 }
139         }
140         
141         /* cleanup and return findings */
142         BLI_freelistN(&anim_data);
143         return found;
144 }
145
146 /* Check if there are any visible + editable keyframes (for editing tools) */
147 int graphop_editable_keyframes_poll (bContext *C)
148 {
149         bAnimContext ac;
150         bAnimListElem *ale;
151         ListBase anim_data = {NULL, NULL};
152         ScrArea *sa= CTX_wm_area(C);
153         size_t items;
154         int filter;
155         short found = 0;
156         
157         /* firstly, check if in Graph Editor */
158         // TODO: also check for region?
159         if ((sa == NULL) || (sa->spacetype != SPACE_IPO))
160                 return 0;
161                 
162         /* try to init Anim-Context stuff ourselves and check */
163         if (ANIM_animdata_get_context(C, &ac) == 0)
164                 return 0;
165         
166         /* loop over the editable F-Curves, and see if they're suitable
167          * stopping on the first successful match
168          */
169         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
170         items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
171         if (items == 0) 
172                 return 0;
173         
174         for (ale = anim_data.first; ale; ale= ale->next) {
175                 FCurve *fcu= (FCurve *)ale->data;
176                 
177                 /* editable curves must fulfull the following criteria:
178                  *      - it has bezier keyframes
179                  *      - it must not be protected from editing (this is already checked for with the foredit flag
180                  *      - F-Curve modifiers do not interfere with the result too much 
181                  *        (i.e. the modifier-control drawing check returns false)
182                  */
183                 if (fcu->bezt == NULL)
184                         continue;
185                 if (fcurve_is_keyframable(fcu)) {
186                         found = 1;
187                         break;
188                 }
189         }
190         
191         /* cleanup and return findings */
192         BLI_freelistN(&anim_data);
193         return found;
194 }
195
196 /* has active F-Curve that's editable */
197 int graphop_active_fcurve_poll (bContext *C)
198 {
199         bAnimContext ac;
200         bAnimListElem *ale;
201         ScrArea *sa= CTX_wm_area(C);
202         short has_fcurve= 0;
203         
204         /* firstly, check if in Graph Editor */
205         // TODO: also check for region?
206         if ((sa == NULL) || (sa->spacetype != SPACE_IPO))
207                 return 0;
208                 
209         /* try to init Anim-Context stuff ourselves and check */
210         if (ANIM_animdata_get_context(C, &ac) == 0)
211                 return 0;
212                 
213         /* try to get the Active F-Curve */
214         ale= get_active_fcurve_channel(&ac);
215         if (ale == NULL)
216                 return 0;
217                 
218         /* free temp data... */
219         has_fcurve= ((ale->data) && (ale->type == ANIMTYPE_FCURVE));
220         if (has_fcurve) {
221                 FCurve *fcu= (FCurve *)ale->data;
222                 has_fcurve= (fcu->flag & FCURVE_VISIBLE)!=0;
223         }
224         
225         MEM_freeN(ale);
226         
227         /* return success */
228         return has_fcurve;
229 }
230
231 /* has selected F-Curve that's editable */
232 int graphop_selected_fcurve_poll (bContext *C)
233 {
234         bAnimContext ac;
235         ListBase anim_data = {NULL, NULL};
236         ScrArea *sa= CTX_wm_area(C);
237         size_t items;
238         int filter;
239         
240         /* firstly, check if in Graph Editor */
241         // TODO: also check for region?
242         if ((sa == NULL) || (sa->spacetype != SPACE_IPO))
243                 return 0;
244                 
245         /* try to init Anim-Context stuff ourselves and check */
246         if (ANIM_animdata_get_context(C, &ac) == 0)
247                 return 0;
248         
249         /* get the editable + selected F-Curves, and as long as we got some, we can return 
250          * NOTE: curve-visible flag isn't included, otherwise selecting a curve via list to edit is too cumbersome
251          */
252         filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
253         items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
254         if (items == 0) 
255                 return 0;
256         
257         /* cleanup and return findings */
258         BLI_freelistN(&anim_data);
259         return 1;
260 }
261
262 /* ************************************************************** */