Merged changes in the trunk up to revision 51718.
[blender.git] / source / blender / editors / space_nla / nla_buttons.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2009 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation, Joshua Leung
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_nla/nla_buttons.c
28  *  \ingroup spnla
29  */
30
31
32 #include <string.h>
33 #include <stdio.h>
34 #include <math.h>
35 #include <float.h>
36
37 #include "DNA_anim_types.h"
38
39 #include "BLI_utildefines.h"
40
41 #include "MEM_guardedalloc.h"
42
43 #include "BLI_math.h"
44 #include "BLI_blenlib.h"
45 #include "BLI_rand.h"
46
47 #include "BLF_translation.h"
48
49 #include "BKE_nla.h"
50 #include "BKE_context.h"
51 #include "BKE_screen.h"
52
53
54 #include "WM_api.h"
55 #include "WM_types.h"
56
57 #include "RNA_access.h"
58
59 #include "ED_anim_api.h"
60 #include "ED_screen.h"
61
62 #include "UI_interface.h"
63 #include "UI_resources.h"
64
65 #include "nla_intern.h" // own include
66
67
68 /* ******************* nla editor space & buttons ************** */
69
70 /* -------------- */
71
72 static void do_nla_region_buttons(bContext *C, void *UNUSED(arg), int event)
73 {
74         //Scene *scene = CTX_data_scene(C);
75         
76         switch (event) {
77
78         }
79         
80         /* default for now */
81         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
82         WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM, NULL);
83 }
84
85 static int nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_ptr, PointerRNA *strip_ptr)
86 {
87         bAnimContext ac;
88         bAnimListElem *ale = NULL;
89         ListBase anim_data = {NULL, NULL};
90         short found = 0;
91         int filter;
92         
93         /* for now, only draw if we could init the anim-context info (necessary for all animation-related tools) 
94          * to work correctly is able to be correctly retrieved. There's no point showing empty panels?
95          */
96         if (ANIM_animdata_get_context(C, &ac) == 0) 
97                 return 0;
98         
99         /* extract list of active channel(s), of which we should only take the first one 
100          *      - we need the channels flag to get the active AnimData block when there are no NLA Tracks
101          */
102         // XXX: double-check active!
103         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_LIST_CHANNELS);
104         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
105         
106         for (ale = anim_data.first; ale; ale = ale->next) {
107                 switch (ale->type) {
108                         case ANIMTYPE_NLATRACK: /* NLA Track - The primary data type which should get caught */
109                         {
110                                 NlaTrack *nlt = (NlaTrack *)ale->data;
111                                 AnimData *adt = ale->adt;
112                                 
113                                 /* found it, now set the pointers */
114                                 if (adt_ptr) {
115                                         /* AnimData pointer */
116                                         RNA_pointer_create(ale->id, &RNA_AnimData, adt, adt_ptr);
117                                 }
118                                 if (nlt_ptr) {
119                                         /* NLA-Track pointer */
120                                         RNA_pointer_create(ale->id, &RNA_NlaTrack, nlt, nlt_ptr);
121                                 }
122                                 if (strip_ptr) {
123                                         /* NLA-Strip pointer */
124                                         NlaStrip *strip = BKE_nlastrip_find_active(nlt);
125                                         RNA_pointer_create(ale->id, &RNA_NlaStrip, strip, strip_ptr);
126                                 }
127                                 
128                                 found = 1;
129                         }
130                         break;
131                                 
132                         case ANIMTYPE_SCENE:    /* Top-Level Widgets doubling up as datablocks */
133                         case ANIMTYPE_OBJECT:
134                         case ANIMTYPE_FILLACTD: /* Action Expander */
135                         case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
136                         case ANIMTYPE_DSLAM:
137                         case ANIMTYPE_DSCAM:
138                         case ANIMTYPE_DSCUR:
139                         case ANIMTYPE_DSSKEY:
140                         case ANIMTYPE_DSWOR:
141                         case ANIMTYPE_DSNTREE:
142                         case ANIMTYPE_DSPART:
143                         case ANIMTYPE_DSMBALL:
144                         case ANIMTYPE_DSARM:
145                         case ANIMTYPE_DSLINESTYLE:
146                         case ANIMTYPE_DSSPK:
147                         {
148                                 /* for these channels, we only do AnimData */
149                                 if (ale->id && ale->adt) {
150                                         if (adt_ptr) {
151                                                 /* AnimData pointer */
152                                                 RNA_pointer_create(ale->id, &RNA_AnimData, ale->adt, adt_ptr);
153                                                 
154                                                 /* set found status to -1, since setting to 1 would break the loop 
155                                                  * and potentially skip an active NLA-Track in some cases...
156                                                  */
157                                                 found = -1;
158                                         }
159                                 }
160                         }
161                         break;
162                 }
163                 
164                 if (found > 0)
165                         break;
166         }
167         
168         /* free temp data */
169         BLI_freelistN(&anim_data);
170         
171         return found;
172 }
173
174 #if 0
175 static int nla_panel_poll(const bContext *C, PanelType *pt)
176 {
177         return nla_panel_context(C, NULL, NULL);
178 }
179 #endif
180
181 static int nla_animdata_panel_poll(const bContext *C, PanelType *UNUSED(pt))
182 {
183         PointerRNA ptr;
184         return (nla_panel_context(C, &ptr, NULL, NULL) && (ptr.data != NULL));
185 }
186
187 static int nla_track_panel_poll(const bContext *C, PanelType *UNUSED(pt))
188 {
189         PointerRNA ptr;
190         return (nla_panel_context(C, NULL, &ptr, NULL) && (ptr.data != NULL));
191 }
192
193 static int nla_strip_panel_poll(const bContext *C, PanelType *UNUSED(pt))
194 {
195         PointerRNA ptr;
196         return (nla_panel_context(C, NULL, NULL, &ptr) && (ptr.data != NULL));
197 }
198
199 static int nla_strip_actclip_panel_poll(const bContext *C, PanelType *UNUSED(pt))
200 {
201         PointerRNA ptr;
202         NlaStrip *strip;
203         
204         if (!nla_panel_context(C, NULL, NULL, &ptr))
205                 return 0;
206         if (ptr.data == NULL)
207                 return 0;
208         
209         strip = ptr.data;
210         return (strip->type == NLASTRIP_TYPE_CLIP);
211 }
212
213 static int nla_strip_eval_panel_poll(const bContext *C, PanelType *UNUSED(pt))
214 {
215         PointerRNA ptr;
216         NlaStrip *strip;
217         
218         if (!nla_panel_context(C, NULL, NULL, &ptr))
219                 return 0;
220         if (ptr.data == NULL)
221                 return 0;
222         
223         strip = ptr.data;
224         
225         if (strip->type == NLASTRIP_TYPE_SOUND)
226                 return 0;
227                 
228         return 1;
229 }
230
231 /* -------------- */
232
233 /* active AnimData */
234 static void nla_panel_animdata(const bContext *C, Panel *pa)
235 {
236         PointerRNA adt_ptr;
237         /* AnimData *adt; */
238         uiLayout *layout = pa->layout;
239         uiLayout *row;
240         uiBlock *block;
241         
242         /* check context and also validity of pointer */
243         if (!nla_panel_context(C, &adt_ptr, NULL, NULL))
244                 return;
245
246         /* adt = adt_ptr.data; */
247         
248         block = uiLayoutGetBlock(layout);
249         uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
250         
251         /* Active Action Properties ------------------------------------- */
252         /* action */
253         row = uiLayoutRow(layout, TRUE);
254         uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACTION_OT_new", NULL, NULL /*"ACTION_OT_unlink"*/);     // XXX: need to make these operators
255         
256         /* extrapolation */
257         row = uiLayoutRow(layout, TRUE);
258         uiItemR(row, &adt_ptr, "action_extrapolation", 0, NULL, ICON_NONE);
259         
260         /* blending */
261         row = uiLayoutRow(layout, TRUE);
262         uiItemR(row, &adt_ptr, "action_blend_type", 0, NULL, ICON_NONE);
263                 
264         /* influence */
265         row = uiLayoutRow(layout, TRUE);
266         uiItemR(row, &adt_ptr, "action_influence", 0, NULL, ICON_NONE);
267 }
268
269 /* active NLA-Track */
270 static void nla_panel_track(const bContext *C, Panel *pa)
271 {
272         PointerRNA nlt_ptr;
273         uiLayout *layout = pa->layout;
274         uiLayout *row;
275         uiBlock *block;
276         
277         /* check context and also validity of pointer */
278         if (!nla_panel_context(C, NULL, &nlt_ptr, NULL))
279                 return;
280         
281         block = uiLayoutGetBlock(layout);
282         uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
283         
284         /* Info - Active NLA-Context:Track ----------------------  */
285         row = uiLayoutRow(layout, TRUE);
286         uiItemR(row, &nlt_ptr, "name", 0, NULL, ICON_NLA);
287 }
288
289 /* generic settings for active NLA-Strip */
290 static void nla_panel_properties(const bContext *C, Panel *pa)
291 {
292         PointerRNA strip_ptr;
293         uiLayout *layout = pa->layout;
294         uiLayout *column, *row, *sub;
295         uiBlock *block;
296         short showEvalProps = 1;
297         
298         if (!nla_panel_context(C, NULL, NULL, &strip_ptr))
299                 return;
300         
301         block = uiLayoutGetBlock(layout);
302         uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
303         
304         /* Strip Properties ------------------------------------- */
305         /* strip type */
306         row = uiLayoutColumn(layout, TRUE);
307         uiItemR(row, &strip_ptr, "name", 0, NULL, ICON_NLA);     // XXX icon?
308         uiItemR(row, &strip_ptr, "type", 0, NULL, ICON_NONE);
309         
310         /* strip extents */
311         column = uiLayoutColumn(layout, TRUE);
312         uiItemL(column, "Strip Extents:", ICON_NONE);
313         uiItemR(column, &strip_ptr, "frame_start", 0, NULL, ICON_NONE);
314         uiItemR(column, &strip_ptr, "frame_end", 0, NULL, ICON_NONE);
315         
316         /* Evaluation-Related Strip Properties ------------------ */
317         
318         /* sound properties strips don't have these settings */
319         if (RNA_enum_get(&strip_ptr, "type") == NLASTRIP_TYPE_SOUND)
320                 showEvalProps = 0;
321         
322         /* only show if allowed to... */
323         if (showEvalProps) {
324                 /* extrapolation */
325                 row = uiLayoutRow(layout, TRUE);
326                 uiItemR(row, &strip_ptr, "extrapolation", 0, NULL, ICON_NONE);
327                 
328                 /* blending */
329                 row = uiLayoutRow(layout, TRUE);
330                 uiItemR(row, &strip_ptr, "blend_type", 0, NULL, ICON_NONE);
331                         
332                 /* blend in/out + autoblending
333                  *      - blend in/out can only be set when autoblending is off
334                  */
335                 column = uiLayoutColumn(layout, TRUE);
336                 uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_animated_influence") == FALSE);
337                 uiItemR(column, &strip_ptr, "use_auto_blend", 0, NULL, ICON_NONE);     // XXX as toggle?
338
339                 sub = uiLayoutColumn(column, TRUE);
340                 uiLayoutSetActive(sub, RNA_boolean_get(&strip_ptr, "use_auto_blend") == FALSE);
341                 uiItemR(sub, &strip_ptr, "blend_in", 0, NULL, ICON_NONE);
342                 uiItemR(sub, &strip_ptr, "blend_out", 0, NULL, ICON_NONE);
343                         
344                 /* settings */
345                 column = uiLayoutColumn(layout, TRUE);
346                 uiLayoutSetActive(column, !(RNA_boolean_get(&strip_ptr, "use_animated_influence") || RNA_boolean_get(&strip_ptr, "use_animated_time")));
347                 uiItemL(column, "Playback Settings:", ICON_NONE);
348                 uiItemR(column, &strip_ptr, "mute", 0, NULL, ICON_NONE);
349                 uiItemR(column, &strip_ptr, "use_reverse", 0, NULL, ICON_NONE);
350         }
351 }
352
353
354 /* action-clip only settings for active NLA-Strip */
355 static void nla_panel_actclip(const bContext *C, Panel *pa)
356 {
357         PointerRNA strip_ptr;
358         uiLayout *layout = pa->layout;
359         uiLayout *column, *row;
360         uiBlock *block;
361
362         /* check context and also validity of pointer */
363         if (!nla_panel_context(C, NULL, NULL, &strip_ptr))
364                 return;
365         
366         block = uiLayoutGetBlock(layout);
367         uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
368                 
369         /* Strip Properties ------------------------------------- */
370         /* action pointer */
371         row = uiLayoutRow(layout, TRUE);
372         uiItemR(row, &strip_ptr, "action", 0, NULL, ICON_ACTION);
373                 
374         /* action extents */
375         // XXX custom names were used here (to avoid the prefixes)... probably not necessary in future?
376         column = uiLayoutColumn(layout, TRUE);
377         uiItemL(column, "Action Extents:", ICON_NONE);
378         uiItemR(column, &strip_ptr, "action_frame_start", 0, "Start Frame", ICON_NONE);
379         uiItemR(column, &strip_ptr, "action_frame_end", 0, "End Frame", ICON_NONE);
380         uiItemO(column, NULL, ICON_NONE, "NLA_OT_action_sync_length");
381                 
382         /* action usage */
383         column = uiLayoutColumn(layout, TRUE);
384         uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_animated_time") == FALSE);
385         uiItemL(column, "Playback Settings:", ICON_NONE);
386         uiItemR(column, &strip_ptr, "scale", 0, NULL, ICON_NONE);
387         uiItemR(column, &strip_ptr, "repeat", 0, NULL, ICON_NONE);
388 }
389
390 /* evaluation settings for active NLA-Strip */
391 static void nla_panel_evaluation(const bContext *C, Panel *pa)
392 {
393         PointerRNA strip_ptr;
394         uiLayout *layout = pa->layout;
395         uiLayout *col, *sub;
396         uiBlock *block;
397
398         /* check context and also validity of pointer */
399         if (!nla_panel_context(C, NULL, NULL, &strip_ptr))
400                 return;
401                 
402         block = uiLayoutGetBlock(layout);
403         uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
404                 
405         col = uiLayoutColumn(layout, TRUE);
406         uiItemR(col, &strip_ptr, "use_animated_influence", 0, NULL, ICON_NONE);
407         
408         sub = uiLayoutColumn(col, TRUE);
409         uiLayoutSetEnabled(sub, RNA_boolean_get(&strip_ptr, "use_animated_influence"));
410         uiItemR(sub, &strip_ptr, "influence", 0, NULL, ICON_NONE);
411
412         col = uiLayoutColumn(layout, TRUE);
413         sub = uiLayoutRow(col, FALSE);
414         uiItemR(sub, &strip_ptr, "use_animated_time", 0, NULL, ICON_NONE);
415         uiItemR(sub, &strip_ptr, "use_animated_time_cyclic", 0, NULL, ICON_NONE);
416
417         sub = uiLayoutRow(col, FALSE);
418         uiLayoutSetEnabled(sub, RNA_boolean_get(&strip_ptr, "use_animated_time"));
419         uiItemR(sub, &strip_ptr, "strip_time", 0, NULL, ICON_NONE);
420 }
421
422 /* F-Modifiers for active NLA-Strip */
423 static void nla_panel_modifiers(const bContext *C, Panel *pa)
424 {
425         PointerRNA strip_ptr;
426         NlaStrip *strip;
427         FModifier *fcm;
428         uiLayout *col, *row;
429         uiBlock *block;
430
431         /* check context and also validity of pointer */
432         if (!nla_panel_context(C, NULL, NULL, &strip_ptr))
433                 return;
434         strip = strip_ptr.data;
435                 
436         block = uiLayoutGetBlock(pa->layout);
437         uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
438         
439         /* 'add modifier' button at top of panel */
440         {
441                 row = uiLayoutRow(pa->layout, FALSE);
442                 block = uiLayoutGetBlock(row);
443                 
444                 // XXX for now, this will be a operator button which calls a temporary 'add modifier' operator
445                 // FIXME: we need to set the only-active property so that this will only add modifiers for the active strip (not all selected)
446                 uiDefButO(block, BUT, "NLA_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, IFACE_("Add Modifier"), 10, 0, 150, 20,
447                           TIP_("Adds a new F-Modifier for the active NLA Strip"));
448                 
449                 /* copy/paste (as sub-row)*/
450                 row = uiLayoutRow(row, TRUE);
451                 uiItemO(row, "", ICON_COPYDOWN, "NLA_OT_fmodifier_copy");
452                 uiItemO(row, "", ICON_PASTEDOWN, "NLA_OT_fmodifier_paste");
453         }
454         
455         /* draw each modifier */
456         for (fcm = strip->modifiers.first; fcm; fcm = fcm->next) {
457                 col = uiLayoutColumn(pa->layout, TRUE);
458                 
459                 ANIM_uiTemplate_fmodifier_draw(col, strip_ptr.id.data, &strip->modifiers, fcm);
460         }
461 }
462
463 /* ******************* general ******************************** */
464
465
466 void nla_buttons_register(ARegionType *art)
467 {
468         PanelType *pt;
469         
470         pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel animdata");
471         strcpy(pt->idname, "NLA_PT_animdata");
472         strcpy(pt->label, "Animation Data");
473         pt->draw = nla_panel_animdata;
474         pt->poll = nla_animdata_panel_poll;
475         pt->flag = PNL_DEFAULT_CLOSED;
476         BLI_addtail(&art->paneltypes, pt);
477         
478         pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel track");
479         strcpy(pt->idname, "NLA_PT_track");
480         strcpy(pt->label, "Active Track");
481         pt->draw = nla_panel_track;
482         pt->poll = nla_track_panel_poll;
483         BLI_addtail(&art->paneltypes, pt);
484         
485         pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
486         strcpy(pt->idname, "NLA_PT_properties");
487         strcpy(pt->label, "Active Strip");
488         pt->draw = nla_panel_properties;
489         pt->poll = nla_strip_panel_poll;
490         BLI_addtail(&art->paneltypes, pt);
491         
492         pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
493         strcpy(pt->idname, "NLA_PT_actionclip");
494         strcpy(pt->label, "Action Clip");
495         pt->draw = nla_panel_actclip;
496         pt->poll = nla_strip_actclip_panel_poll;
497         BLI_addtail(&art->paneltypes, pt);
498         
499         pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel evaluation");
500         strcpy(pt->idname, "NLA_PT_evaluation");
501         strcpy(pt->label, "Evaluation");
502         pt->draw = nla_panel_evaluation;
503         pt->poll = nla_strip_eval_panel_poll;
504         BLI_addtail(&art->paneltypes, pt);
505         
506         pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel modifiers");
507         strcpy(pt->idname, "NLA_PT_modifiers");
508         strcpy(pt->label, "Modifiers");
509         pt->draw = nla_panel_modifiers;
510         pt->poll = nla_strip_eval_panel_poll;
511         BLI_addtail(&art->paneltypes, pt);
512 }
513
514 static int nla_properties(bContext *C, wmOperator *UNUSED(op))
515 {
516         ScrArea *sa = CTX_wm_area(C);
517         ARegion *ar = nla_has_buttons_region(sa);
518         
519         if (ar)
520                 ED_region_toggle_hidden(C, ar);
521
522         return OPERATOR_FINISHED;
523 }
524
525 void NLA_OT_properties(wmOperatorType *ot)
526 {
527         ot->name = "Properties";
528         ot->idname = "NLA_OT_properties";
529         ot->description = "Toggle display properties panel";
530         
531         ot->exec = nla_properties;
532         ot->poll = ED_operator_nla_active;
533
534         /* flags */
535         ot->flag = 0;
536 }