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