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) 2009 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup spgraph
22  */
23 
24 #include <float.h>
25 #include <math.h>
26 #include <stdio.h>
27 #include <string.h>
28 
29 #include "DNA_anim_types.h"
30 #include "DNA_screen_types.h"
31 #include "DNA_space_types.h"
32 
33 #include "MEM_guardedalloc.h"
34 
35 #include "BLI_blenlib.h"
36 
37 #include "BKE_context.h"
38 #include "BKE_fcurve.h"
39 #include "BKE_screen.h"
40 
41 #include "WM_api.h"
42 
43 #include "ED_anim_api.h"
44 #include "ED_screen.h"
45 #include "UI_interface.h"
46 
47 #include "RNA_access.h"
48 
49 #include "graph_intern.h" /* own include */
50 
51 /* ************************************************************** */
52 /* Set Up Drivers Editor */
53 
54 /* Set up UI configuration for Drivers Editor */
55 /* NOTE: Currently called from window-manager
56  * (new drivers editor window) and RNA (mode switching) */
ED_drivers_editor_init(bContext * C,ScrArea * area)57 void ED_drivers_editor_init(bContext *C, ScrArea *area)
58 {
59   SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
60 
61   /* Set mode */
62   sipo->mode = SIPO_MODE_DRIVERS;
63 
64   /* Show Properties Region (or else the settings can't be edited) */
65   ARegion *region_props = BKE_area_find_region_type(area, RGN_TYPE_UI);
66   if (region_props) {
67     UI_panel_category_active_set(region_props, "Drivers");
68 
69     region_props->flag &= ~RGN_FLAG_HIDDEN;
70     /* XXX: Adjust width of this too? */
71 
72     ED_region_visibility_change_update(C, area, region_props);
73   }
74   else {
75     printf("%s: Couldn't find properties region for Drivers Editor - %p\n", __func__, area);
76   }
77 
78   /* Adjust framing in graph region */
79   /* TODO: Have a way of not resetting this every time?
80    * (e.g. So that switching back and forth between editors doesn't keep jumping?)
81    */
82   ARegion *region_main = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
83   if (region_main) {
84     /* XXX: Ideally we recenter based on the range instead... */
85     region_main->v2d.tot.xmin = -2.0f;
86     region_main->v2d.tot.ymin = -2.0f;
87     region_main->v2d.tot.xmax = 2.0f;
88     region_main->v2d.tot.ymax = 2.0f;
89 
90     region_main->v2d.cur = region_main->v2d.tot;
91   }
92 }
93 
94 /* ************************************************************** */
95 /* Active F-Curve */
96 
97 /**
98  * Find 'active' F-Curve.
99  * It must be editable, since that's the purpose of these buttons (subject to change).
100  * We return the 'wrapper' since it contains valuable context info (about hierarchy),
101  * which will need to be freed when the caller is done with it.
102  *
103  * \note curve-visible flag isn't included,
104  * otherwise selecting a curve via list to edit is too cumbersome.
105  */
get_active_fcurve_channel(bAnimContext * ac)106 bAnimListElem *get_active_fcurve_channel(bAnimContext *ac)
107 {
108   ListBase anim_data = {NULL, NULL};
109   int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_ACTIVE);
110   size_t items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
111 
112   /* We take the first F-Curve only, since some other ones may have had 'active' flag set
113    * if they were from linked data.
114    */
115   if (items) {
116     bAnimListElem *ale = (bAnimListElem *)anim_data.first;
117 
118     /* remove first item from list, then free the rest of the list and return the stored one */
119     BLI_remlink(&anim_data, ale);
120     ANIM_animdata_freelist(&anim_data);
121 
122     return ale;
123   }
124 
125   /* no active F-Curve */
126   return NULL;
127 }
128 
129 /* ************************************************************** */
130 /* Operator Polling Callbacks */
131 
132 /* Check if there are any visible keyframes (for selection tools) */
graphop_visible_keyframes_poll(bContext * C)133 bool graphop_visible_keyframes_poll(bContext *C)
134 {
135   bAnimContext ac;
136   bAnimListElem *ale;
137   ListBase anim_data = {NULL, NULL};
138   ScrArea *area = CTX_wm_area(C);
139   size_t items;
140   int filter;
141   bool found = false;
142 
143   /* firstly, check if in Graph Editor */
144   /* TODO: also check for region? */
145   if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
146     return found;
147   }
148 
149   /* try to init Anim-Context stuff ourselves and check */
150   if (ANIM_animdata_get_context(C, &ac) == 0) {
151     return found;
152   }
153 
154   /* loop over the visible (selection doesn't matter) F-Curves, and see if they're suitable
155    * stopping on the first successful match
156    */
157   filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE);
158   items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
159   if (items == 0) {
160     return found;
161   }
162 
163   for (ale = anim_data.first; ale; ale = ale->next) {
164     FCurve *fcu = (FCurve *)ale->data;
165 
166     /* visible curves for selection must fulfill the following criteria:
167      * - it has bezier keyframes
168      * - F-Curve modifiers do not interfere with the result too much
169      *   (i.e. the modifier-control drawing check returns false)
170      */
171     if (fcu->bezt == NULL) {
172       continue;
173     }
174     if (BKE_fcurve_are_keyframes_usable(fcu)) {
175       found = true;
176       break;
177     }
178   }
179 
180   /* cleanup and return findings */
181   ANIM_animdata_freelist(&anim_data);
182   return found;
183 }
184 
185 /* Check if there are any visible + editable keyframes (for editing tools) */
graphop_editable_keyframes_poll(bContext * C)186 bool graphop_editable_keyframes_poll(bContext *C)
187 {
188   bAnimContext ac;
189   bAnimListElem *ale;
190   ListBase anim_data = {NULL, NULL};
191   ScrArea *area = CTX_wm_area(C);
192   size_t items;
193   int filter;
194   bool found = false;
195 
196   /* firstly, check if in Graph Editor */
197   /* TODO: also check for region? */
198   if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
199     return found;
200   }
201 
202   /* try to init Anim-Context stuff ourselves and check */
203   if (ANIM_animdata_get_context(C, &ac) == 0) {
204     return found;
205   }
206 
207   /* loop over the editable F-Curves, and see if they're suitable
208    * stopping on the first successful match
209    */
210   filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVE_VISIBLE);
211   items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
212   if (items == 0) {
213     return found;
214   }
215 
216   for (ale = anim_data.first; ale; ale = ale->next) {
217     FCurve *fcu = (FCurve *)ale->data;
218 
219     /* editable curves must fulfill the following criteria:
220      * - it has bezier keyframes
221      * - it must not be protected from editing (this is already checked for with the edit flag
222      * - F-Curve modifiers do not interfere with the result too much
223      *   (i.e. the modifier-control drawing check returns false)
224      */
225     if (fcu->bezt == NULL && fcu->fpt != NULL) {
226       /* This is a baked curve, it is never editable. */
227       continue;
228     }
229     if (BKE_fcurve_is_keyframable(fcu)) {
230       found = true;
231       break;
232     }
233   }
234 
235   /* cleanup and return findings */
236   ANIM_animdata_freelist(&anim_data);
237   return found;
238 }
239 
240 /* has active F-Curve that's editable */
graphop_active_fcurve_poll(bContext * C)241 bool graphop_active_fcurve_poll(bContext *C)
242 {
243   bAnimContext ac;
244   bAnimListElem *ale;
245   ScrArea *area = CTX_wm_area(C);
246   bool has_fcurve = false;
247 
248   /* firstly, check if in Graph Editor */
249   /* TODO: also check for region? */
250   if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
251     return has_fcurve;
252   }
253 
254   /* try to init Anim-Context stuff ourselves and check */
255   if (ANIM_animdata_get_context(C, &ac) == 0) {
256     return has_fcurve;
257   }
258 
259   /* try to get the Active F-Curve */
260   ale = get_active_fcurve_channel(&ac);
261   if (ale == NULL) {
262     return has_fcurve;
263   }
264 
265   /* Do we have a suitable F-Curves?
266    * - For most cases, NLA Control Curves are sufficiently similar to NLA
267    *   curves to serve this role too. Under the hood, they are F-Curves too.
268    *   The only problems which will arise here are if these need to be
269    *   in an Action too (but drivers would then also be affected!)
270    */
271   has_fcurve = ((ale->data) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE));
272   if (has_fcurve) {
273     FCurve *fcu = (FCurve *)ale->data;
274     has_fcurve = (fcu->flag & FCURVE_VISIBLE) != 0;
275   }
276 
277   /* free temp data... */
278   MEM_freeN(ale);
279 
280   /* return success */
281   return has_fcurve;
282 }
283 
284 /* has active F-Curve in the context that's editable */
graphop_active_editable_fcurve_ctx_poll(bContext * C)285 bool graphop_active_editable_fcurve_ctx_poll(bContext *C)
286 {
287   PointerRNA ptr = CTX_data_pointer_get_type(C, "active_editable_fcurve", &RNA_FCurve);
288 
289   return ptr.data != NULL;
290 }
291 
292 /* has selected F-Curve that's editable */
graphop_selected_fcurve_poll(bContext * C)293 bool graphop_selected_fcurve_poll(bContext *C)
294 {
295   bAnimContext ac;
296   ListBase anim_data = {NULL, NULL};
297   ScrArea *area = CTX_wm_area(C);
298   size_t items;
299   int filter;
300 
301   /* firstly, check if in Graph Editor */
302   /* TODO: also check for region? */
303   if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
304     return false;
305   }
306 
307   /* try to init Anim-Context stuff ourselves and check */
308   if (ANIM_animdata_get_context(C, &ac) == 0) {
309     return false;
310   }
311 
312   /* Get the editable + selected F-Curves, and as long as we got some, we can return.
313    * NOTE: curve-visible flag isn't included,
314    * otherwise selecting a curve via list to edit is too cumbersome. */
315   filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
316   items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
317   if (items == 0) {
318     return false;
319   }
320 
321   /* cleanup and return findings */
322   ANIM_animdata_freelist(&anim_data);
323   return true;
324 }
325 
326 /* ************************************************************** */
327