Dopesheet: Keyframe size can be adjusted as part of theme settings
[blender.git] / source / blender / editors / animation / fmodifier_ui.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/animation/fmodifier_ui.c
28  *  \ingroup edanimation
29  */
30
31
32 /* User-Interface Stuff for F-Modifiers:
33  * This file defines the (C-Coded) templates + editing callbacks needed 
34  * by the interface stuff or F-Modifiers, as used by F-Curves in the Graph Editor,
35  * and NLA-Strips in the NLA Editor.
36  *
37  * Copy/Paste Buffer for F-Modifiers:
38  * For now, this is also defined in this file so that it can be shared between the 
39  */
40  
41 #include <string.h>
42
43 #include "DNA_anim_types.h"
44 #include "DNA_scene_types.h"
45
46 #include "MEM_guardedalloc.h"
47
48 #include "BLT_translation.h"
49
50 #include "BLI_blenlib.h"
51 #include "BLI_utildefines.h"
52
53 #include "BKE_context.h"
54 #include "BKE_fcurve.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59 #include "RNA_access.h"
60
61 #include "UI_interface.h"
62 #include "UI_resources.h"
63
64 #include "ED_anim_api.h"
65 #include "ED_util.h"
66
67 /* ********************************************** */
68 /* UI STUFF */
69
70 // XXX! --------------------------------
71 /* temporary definition for limits of float number buttons (FLT_MAX tends to infinity with old system) */
72 #define UI_FLT_MAX  10000.0f
73
74 #define B_REDR                  1
75 #define B_FMODIFIER_REDRAW      20
76
77 /* callback to verify modifier data */
78 static void validate_fmodifier_cb(bContext *UNUSED(C), void *fcm_v, void *UNUSED(arg))
79 {
80         FModifier *fcm = (FModifier *)fcm_v;
81         const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
82         
83         /* call the verify callback on the modifier if applicable */
84         if (fmi && fmi->verify_data)
85                 fmi->verify_data(fcm);
86 }
87
88 /* callback to remove the given modifier  */
89 static void delete_fmodifier_cb(bContext *C, void *fmods_v, void *fcm_v)
90 {
91         ListBase *modifiers = (ListBase *)fmods_v;
92         FModifier *fcm = (FModifier *)fcm_v;
93         
94         /* remove the given F-Modifier from the active modifier-stack */
95         remove_fmodifier(modifiers, fcm);
96
97         ED_undo_push(C, "Delete F-Curve Modifier");
98         
99         /* send notifiers */
100         // XXX for now, this is the only way to get updates in all the right places... but would be nice to have a special one in this case 
101         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
102 }
103
104 /* --------------- */
105         
106 /* draw settings for generator modifier */
107 static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, short width)
108 {
109         FMod_Generator *data = (FMod_Generator *)fcm->data;
110         uiLayout /* *col, */ /* UNUSED */ *row;
111         uiBlock *block;
112         uiBut *but;
113         PointerRNA ptr;
114         short bwidth = width - 1.5 * UI_UNIT_X; /* max button width */
115         
116         /* init the RNA-pointer */
117         RNA_pointer_create(id, &RNA_FModifierFunctionGenerator, fcm, &ptr);
118         
119         /* basic settings (backdrop + mode selector + some padding) */
120         /* col = uiLayoutColumn(layout, true); */ /* UNUSED */
121         block = uiLayoutGetBlock(layout);
122         UI_block_align_begin(block);
123         but = uiDefButR(block, UI_BTYPE_MENU, B_FMODIFIER_REDRAW, NULL, 0, 0, bwidth, UI_UNIT_Y, &ptr, "mode", -1, 0, 0, -1, -1, NULL);
124         UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
125         
126         uiDefButR(block, UI_BTYPE_TOGGLE, B_FMODIFIER_REDRAW, NULL, 0, 0, bwidth, UI_UNIT_Y, &ptr, "use_additive", -1, 0, 0, -1, -1, NULL);
127         UI_block_align_end(block);
128         
129         /* now add settings for individual modes */
130         switch (data->mode) {
131                 case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
132                 {
133                         const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
134                         float *cp = NULL;
135                         char xval[32];
136                         unsigned int i;
137                         int maxXWidth;
138                         
139                         /* draw polynomial order selector */
140                         row = uiLayoutRow(layout, false);
141                         block = uiLayoutGetBlock(row);
142                         but = uiDefButI(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Poly Order:"), 0.5f * UI_UNIT_X, 0, bwidth, UI_UNIT_Y,
143                                         &data->poly_order, 1, 100, 0, 0,
144                                         TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)"));
145                         UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
146                         
147                         
148                         /* calculate maximum width of label for "x^n" labels */
149                         if (data->arraysize > 2) {
150                                 BLI_snprintf(xval, sizeof(xval), "x^%u", data->arraysize);
151                                 /* XXX: UI_fontstyle_string_width is not accurate */
152                                 maxXWidth = UI_fontstyle_string_width(fstyle, xval) + 0.5 * UI_UNIT_X;
153                         }
154                         else {
155                                 /* basic size (just "x") */
156                                 maxXWidth = UI_fontstyle_string_width(fstyle, "x") + 0.5 * UI_UNIT_X;
157                         }
158                         
159                         /* draw controls for each coefficient and a + sign at end of row */
160                         row = uiLayoutRow(layout, true);
161                         block = uiLayoutGetBlock(row);
162                         
163                         cp = data->coefficients;
164                         for (i = 0; (i < data->arraysize) && (cp); i++, cp++) {
165                                 /* To align with first line... */
166                                 if (i)
167                                         uiDefBut(block, UI_BTYPE_LABEL, 1, "   ", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
168                                 else
169                                         uiDefBut(block, UI_BTYPE_LABEL, 1, "y =", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
170                                 
171                                 /* coefficient */
172                                 uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, "", 0, 0, bwidth / 2, UI_UNIT_Y, cp, -UI_FLT_MAX, UI_FLT_MAX,
173                                           10, 3, TIP_("Coefficient for polynomial"));
174                                 
175                                 /* 'x' param (and '+' if necessary) */
176                                 if (i == 0)
177                                         BLI_strncpy(xval, "", sizeof(xval));
178                                 else if (i == 1)
179                                         BLI_strncpy(xval, "x", sizeof(xval));
180                                 else
181                                         BLI_snprintf(xval, sizeof(xval), "x^%u", i);
182                                 uiDefBut(block, UI_BTYPE_LABEL, 1, xval, 0, 0, maxXWidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, TIP_("Power of x"));
183                                 
184                                 if ( (i != (data->arraysize - 1)) || ((i == 0) && data->arraysize == 2) ) {
185                                         uiDefBut(block, UI_BTYPE_LABEL, 1, "+", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
186                                         
187                                         /* next coefficient on a new row */
188                                         row = uiLayoutRow(layout, true);
189                                         block = uiLayoutGetBlock(row);
190                                 }
191                                 else {
192                                         /* For alignment in UI! */
193                                         uiDefBut(block, UI_BTYPE_LABEL, 1, " ", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
194                                 }
195                         }
196                         break;
197                 }
198                 
199                 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* Factorized polynomial expression */
200                 {
201                         float *cp = NULL;
202                         unsigned int i;
203                         
204                         /* draw polynomial order selector */
205                         row = uiLayoutRow(layout, false);
206                         block = uiLayoutGetBlock(row);
207                         but = uiDefButI(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Poly Order:"), 0, 0, width - 1.5 * UI_UNIT_X, UI_UNIT_Y,
208                                         &data->poly_order, 1, 100, 0, 0,
209                                         TIP_("'Order' of the Polynomial (for a polynomial with n terms, 'order' is n-1)"));
210                         UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
211                         
212                         
213                         /* draw controls for each pair of coefficients */
214                         row = uiLayoutRow(layout, true);
215                         block = uiLayoutGetBlock(row);
216                         
217                         cp = data->coefficients;
218                         for (i = 0; (i < data->poly_order) && (cp); i++, cp += 2) {
219                                 /* To align with first line */
220                                 if (i)
221                                         uiDefBut(block, UI_BTYPE_LABEL, 1, "   ", 0, 0, 2.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
222                                 else
223                                         uiDefBut(block, UI_BTYPE_LABEL, 1, "y =", 0, 0, 2.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
224                                 /* opening bracket */
225                                 uiDefBut(block, UI_BTYPE_LABEL, 1, "(", 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
226                                 
227                                 /* coefficients */
228                                 uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, "", 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y, cp, -UI_FLT_MAX, UI_FLT_MAX,
229                                           10, 3, TIP_("Coefficient of x"));
230                                 
231                                 uiDefBut(block, UI_BTYPE_LABEL, 1, "x +", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
232                                 
233                                 uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, "", 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y, cp + 1, -UI_FLT_MAX, UI_FLT_MAX,
234                                           10, 3, TIP_("Second coefficient"));
235                                 
236                                 /* closing bracket and multiplication sign */
237                                 if ( (i != (data->poly_order - 1)) || ((i == 0) && data->poly_order == 2) ) {
238                                         uiDefBut(block, UI_BTYPE_LABEL, 1, ") \xc3\x97", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
239                                         
240                                         /* set up new row for the next pair of coefficients */
241                                         row = uiLayoutRow(layout, true);
242                                         block = uiLayoutGetBlock(row);
243                                 }
244                                 else 
245                                         uiDefBut(block, UI_BTYPE_LABEL, 1, ")  ", 0, 0, 2 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
246                         }
247                         break;
248                 }
249         }
250 }
251
252 /* --------------- */
253
254 /* draw settings for generator modifier */
255 static void draw_modifier__fn_generator(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
256 {
257         uiLayout *col;
258         PointerRNA ptr;
259         
260         /* init the RNA-pointer */
261         RNA_pointer_create(id, &RNA_FModifierFunctionGenerator, fcm, &ptr);
262         
263         /* add the settings */
264         col = uiLayoutColumn(layout, true);
265         uiItemR(col, &ptr, "function_type", 0, "", ICON_NONE);
266         uiItemR(col, &ptr, "use_additive", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
267
268         col = uiLayoutColumn(layout, false); // no grouping for now
269         uiItemR(col, &ptr, "amplitude", 0, NULL, ICON_NONE);
270         uiItemR(col, &ptr, "phase_multiplier", 0, NULL, ICON_NONE);
271         uiItemR(col, &ptr, "phase_offset", 0, NULL, ICON_NONE);
272         uiItemR(col, &ptr, "value_offset", 0, NULL, ICON_NONE);
273 }
274
275 /* --------------- */
276
277 /* draw settings for cycles modifier */
278 static void draw_modifier__cycles(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
279 {
280         uiLayout *split, *col;
281         PointerRNA ptr;
282         
283         /* init the RNA-pointer */
284         RNA_pointer_create(id, &RNA_FModifierCycles, fcm, &ptr);
285         
286         /* split into 2 columns 
287          * NOTE: the mode comboboxes shouldn't get labels, otherwise there isn't enough room
288          */
289         split = uiLayoutSplit(layout, 0.5f, false);
290         
291         /* before range */
292         col = uiLayoutColumn(split, true);
293         uiItemL(col, IFACE_("Before:"), ICON_NONE);
294         uiItemR(col, &ptr, "mode_before", 0, "", ICON_NONE);
295         uiItemR(col, &ptr, "cycles_before", 0, NULL, ICON_NONE);
296                 
297         /* after range */
298         col = uiLayoutColumn(split, true);
299         uiItemL(col, IFACE_("After:"), ICON_NONE);
300         uiItemR(col, &ptr, "mode_after", 0, "", ICON_NONE);
301         uiItemR(col, &ptr, "cycles_after", 0, NULL, ICON_NONE);
302 }
303
304 /* --------------- */
305
306 /* draw settings for noise modifier */
307 static void draw_modifier__noise(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
308 {
309         uiLayout *split, *col;
310         PointerRNA ptr;
311         
312         /* init the RNA-pointer */
313         RNA_pointer_create(id, &RNA_FModifierNoise, fcm, &ptr);
314         
315         /* blending mode */
316         uiItemR(layout, &ptr, "blend_type", 0, NULL, ICON_NONE);
317         
318         /* split into 2 columns */
319         split = uiLayoutSplit(layout, 0.5f, false);
320         
321         /* col 1 */
322         col = uiLayoutColumn(split, false);
323         uiItemR(col, &ptr, "scale", 0, NULL, ICON_NONE);
324         uiItemR(col, &ptr, "strength", 0, NULL, ICON_NONE);
325         uiItemR(col, &ptr, "offset", 0, NULL, ICON_NONE);
326         
327         /* col 2 */
328         col = uiLayoutColumn(split, false);
329         uiItemR(col, &ptr, "phase", 0, NULL, ICON_NONE);
330         uiItemR(col, &ptr, "depth", 0, NULL, ICON_NONE);
331 }
332
333 /* callback to add new envelope data point */
334 static void fmod_envelope_addpoint_cb(bContext *C, void *fcm_dv, void *UNUSED(arg))
335 {
336         Scene *scene = CTX_data_scene(C);
337         FMod_Envelope *env = (FMod_Envelope *)fcm_dv;
338         FCM_EnvelopeData *fedn;
339         FCM_EnvelopeData fed;
340         
341         /* init template data */
342         fed.min = -1.0f;
343         fed.max = 1.0f;
344         fed.time = (float)scene->r.cfra; // XXX make this int for ease of use?
345         fed.f1 = fed.f2 = 0;
346         
347         /* check that no data exists for the current frame... */
348         if (env->data) {
349                 bool exists;
350                 int i = BKE_fcm_envelope_find_index(env->data, (float)(scene->r.cfra), env->totvert, &exists);
351                 
352                 /* binarysearch_...() will set exists by default to 0, so if it is non-zero, that means that the point exists already */
353                 if (exists)
354                         return;
355                         
356                 /* add new */
357                 fedn = MEM_callocN((env->totvert + 1) * sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
358                 
359                 /* add the points that should occur before the point to be pasted */
360                 if (i > 0)
361                         memcpy(fedn, env->data, i * sizeof(FCM_EnvelopeData));
362                 
363                 /* add point to paste at index i */
364                 *(fedn + i) = fed;
365                 
366                 /* add the points that occur after the point to be pasted */
367                 if (i < env->totvert) 
368                         memcpy(fedn + i + 1, env->data + i, (env->totvert - i) * sizeof(FCM_EnvelopeData));
369                 
370                 /* replace (+ free) old with new */
371                 MEM_freeN(env->data);
372                 env->data = fedn;
373                 
374                 env->totvert++;
375         }
376         else {
377                 env->data = MEM_callocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
378                 *(env->data) = fed;
379                 
380                 env->totvert = 1;
381         }
382 }
383
384 /* callback to remove envelope data point */
385 // TODO: should we have a separate file for things like this?
386 static void fmod_envelope_deletepoint_cb(bContext *UNUSED(C), void *fcm_dv, void *ind_v)
387 {
388         FMod_Envelope *env = (FMod_Envelope *)fcm_dv;
389         FCM_EnvelopeData *fedn;
390         int index = GET_INT_FROM_POINTER(ind_v);
391         
392         /* check that no data exists for the current frame... */
393         if (env->totvert > 1) {
394                 /* allocate a new smaller array */
395                 fedn = MEM_callocN(sizeof(FCM_EnvelopeData) * (env->totvert - 1), "FCM_EnvelopeData");
396
397                 memcpy(fedn, env->data, sizeof(FCM_EnvelopeData) * (index));
398                 memcpy(fedn + index, env->data + (index + 1), sizeof(FCM_EnvelopeData) * ((env->totvert - index) - 1));
399                 
400                 /* free old array, and set the new */
401                 MEM_freeN(env->data);
402                 env->data = fedn;
403                 env->totvert--;
404         }
405         else {
406                 /* just free array, since the only vert was deleted */
407                 if (env->data) {
408                         MEM_freeN(env->data);
409                         env->data = NULL;
410                 }
411                 env->totvert = 0;
412         }
413 }
414
415 /* draw settings for envelope modifier */
416 static void draw_modifier__envelope(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
417 {
418         FMod_Envelope *env = (FMod_Envelope *)fcm->data;
419         FCM_EnvelopeData *fed;
420         uiLayout *col, *row;
421         uiBlock *block;
422         uiBut *but;
423         PointerRNA ptr;
424         int i;
425         
426         /* init the RNA-pointer */
427         RNA_pointer_create(id, &RNA_FModifierEnvelope, fcm, &ptr);
428         
429         /* general settings */
430         col = uiLayoutColumn(layout, true);
431         uiItemL(col, IFACE_("Envelope:"), ICON_NONE);
432         uiItemR(col, &ptr, "reference_value", 0, NULL, ICON_NONE);
433
434         row = uiLayoutRow(col, true);
435         uiItemR(row, &ptr, "default_min", 0, IFACE_("Min"), ICON_NONE);
436         uiItemR(row, &ptr, "default_max", 0, IFACE_("Max"), ICON_NONE);
437
438         /* control points header */
439         /* TODO: move this control-point control stuff to using the new special widgets for lists
440          * the current way is far too cramped */
441         row = uiLayoutRow(layout, false);
442         block = uiLayoutGetBlock(row);
443                 
444         uiDefBut(block, UI_BTYPE_LABEL, 1, IFACE_("Control Points:"), 0, 0, 7.5 * UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
445                 
446         but = uiDefBut(block, UI_BTYPE_BUT, B_FMODIFIER_REDRAW, IFACE_("Add Point"), 0, 0, 7.5 * UI_UNIT_X, UI_UNIT_Y,
447                        NULL, 0, 0, 0, 0, TIP_("Add a new control-point to the envelope on the current frame"));
448         UI_but_func_set(but, fmod_envelope_addpoint_cb, env, NULL);
449                 
450         /* control points list */
451         for (i = 0, fed = env->data; i < env->totvert; i++, fed++) {
452                 /* get a new row to operate on */
453                 row = uiLayoutRow(layout, true);
454                 block = uiLayoutGetBlock(row);
455                 
456                 UI_block_align_begin(block);
457                 but = uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Fra:"), 0, 0, 4.5 * UI_UNIT_X, UI_UNIT_Y,
458                                 &fed->time, -MAXFRAMEF, MAXFRAMEF, 10, 1, TIP_("Frame that envelope point occurs"));
459                 UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
460                         
461                 uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Min:"), 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y,
462                           &fed->min, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, TIP_("Minimum bound of envelope at this point"));
463                 uiDefButF(block, UI_BTYPE_NUM, B_FMODIFIER_REDRAW, IFACE_("Max:"), 0, 0, 5 * UI_UNIT_X, UI_UNIT_Y,
464                           &fed->max, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, TIP_("Maximum bound of envelope at this point"));
465
466                 but = uiDefIconBut(block, UI_BTYPE_BUT, B_FMODIFIER_REDRAW, ICON_X, 0, 0, 0.9 * UI_UNIT_X, UI_UNIT_Y,
467                                    NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete envelope control point"));
468                 UI_but_func_set(but, fmod_envelope_deletepoint_cb, env, SET_INT_IN_POINTER(i));
469                 UI_block_align_begin(block);
470         }
471 }
472
473 /* --------------- */
474
475 /* draw settings for limits modifier */
476 static void draw_modifier__limits(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
477 {
478         uiLayout *split, *col /* , *row */ /* UNUSED */;
479         PointerRNA ptr;
480         
481         /* init the RNA-pointer */
482         RNA_pointer_create(id, &RNA_FModifierLimits, fcm, &ptr);
483         
484         /* row 1: minimum */
485         {
486                 /* row = uiLayoutRow(layout, false); */ /* UNUSED */
487                 
488                 /* split into 2 columns */
489                 split = uiLayoutSplit(layout, 0.5f, false);
490                 
491                 /* x-minimum */
492                 col = uiLayoutColumn(split, true);
493                 uiItemR(col, &ptr, "use_min_x", 0, NULL, ICON_NONE);
494                 uiItemR(col, &ptr, "min_x", 0, NULL, ICON_NONE);
495                         
496                 /* y-minimum*/
497                 col = uiLayoutColumn(split, true);
498                 uiItemR(col, &ptr, "use_min_y", 0, NULL, ICON_NONE);
499                 uiItemR(col, &ptr, "min_y", 0, NULL, ICON_NONE);
500         }
501         
502         /* row 2: maximum */
503         {
504                 /* row = uiLayoutRow(layout, false); */ /* UNUSED */
505                 
506                 /* split into 2 columns */
507                 split = uiLayoutSplit(layout, 0.5f, false);
508                 
509                 /* x-minimum */
510                 col = uiLayoutColumn(split, true);
511                 uiItemR(col, &ptr, "use_max_x", 0, NULL, ICON_NONE);
512                 uiItemR(col, &ptr, "max_x", 0, NULL, ICON_NONE);
513                         
514                 /* y-minimum*/
515                 col = uiLayoutColumn(split, true);
516                 uiItemR(col, &ptr, "use_max_y", 0, NULL, ICON_NONE);
517                 uiItemR(col, &ptr, "max_y", 0, NULL, ICON_NONE);
518         }
519 }
520
521 /* --------------- */
522
523 /* draw settings for stepped interpolation modifier */
524 static void draw_modifier__stepped(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
525 {
526         uiLayout *col, *sub;
527         PointerRNA ptr;
528         
529         /* init the RNA-pointer */
530         RNA_pointer_create(id, &RNA_FModifierStepped, fcm, &ptr);
531         
532         /* block 1: "stepping" settings */
533         col = uiLayoutColumn(layout, false);
534         uiItemR(col, &ptr, "frame_step", 0, NULL, ICON_NONE);
535         uiItemR(col, &ptr, "frame_offset", 0, NULL, ICON_NONE);
536                 
537         /* block 2: start range settings */
538         col = uiLayoutColumn(layout, true);
539         uiItemR(col, &ptr, "use_frame_start", 0, NULL, ICON_NONE);
540                 
541         sub = uiLayoutColumn(col, true);
542         uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_frame_start"));
543         uiItemR(sub, &ptr, "frame_start", 0, NULL, ICON_NONE);
544                         
545         /* block 3: end range settings */
546         col = uiLayoutColumn(layout, true);
547         uiItemR(col, &ptr, "use_frame_end", 0, NULL, ICON_NONE);
548                 
549         sub = uiLayoutColumn(col, true);
550         uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_frame_end"));
551         uiItemR(sub, &ptr, "frame_end", 0, NULL, ICON_NONE);
552 }
553
554 /* --------------- */
555
556 void ANIM_uiTemplate_fmodifier_draw(uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm)
557 {
558         const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
559         uiLayout *box, *row, *sub, *col;
560         uiBlock *block;
561         uiBut *but;
562         short width = 314;
563         PointerRNA ptr;
564         
565         /* init the RNA-pointer */
566         RNA_pointer_create(id, &RNA_FModifier, fcm, &ptr);
567         
568         /* draw header */
569         {
570                 /* get layout-row + UI-block for this */
571                 box = uiLayoutBox(layout);
572                 
573                 row = uiLayoutRow(box, false);
574                 block = uiLayoutGetBlock(row); // err...
575                 
576                 /* left-align -------------------------------------------- */
577                 sub = uiLayoutRow(row, true);
578                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
579                 
580                 UI_block_emboss_set(block, UI_EMBOSS_NONE);
581                 
582                 /* expand */
583                 uiItemR(sub, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
584                 
585                 /* checkbox for 'active' status (for now) */
586                 uiItemR(sub, &ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
587                 
588                 /* name */
589                 if (fmi)
590                         uiItemL(sub, IFACE_(fmi->name), ICON_NONE);
591                 else
592                         uiItemL(sub, IFACE_("<Unknown Modifier>"), ICON_NONE);
593                 
594                 /* right-align ------------------------------------------- */
595                 sub = uiLayoutRow(row, true);
596                 uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
597                 
598                 
599                 /* 'mute' button */
600                 uiItemR(sub, &ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
601                 
602                 UI_block_emboss_set(block, UI_EMBOSS_NONE);
603                 
604                 /* delete button */
605                 but = uiDefIconBut(block, UI_BTYPE_BUT, B_REDR, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y,
606                                    NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Delete F-Curve Modifier"));
607                 UI_but_func_set(but, delete_fmodifier_cb, modifiers, fcm);
608                 
609                 UI_block_emboss_set(block, UI_EMBOSS);
610         }
611         
612         /* when modifier is expanded, draw settings */
613         if (fcm->flag & FMODIFIER_FLAG_EXPANDED) {
614                 /* set up the flexible-box layout which acts as the backdrop for the modifier settings */
615                 box = uiLayoutBox(layout);
616                 
617                 /* draw settings for individual modifiers */
618                 switch (fcm->type) {
619                         case FMODIFIER_TYPE_GENERATOR: /* Generator */
620                                 draw_modifier__generator(box, id, fcm, width);
621                                 break;
622                                 
623                         case FMODIFIER_TYPE_FN_GENERATOR: /* Built-In Function Generator */
624                                 draw_modifier__fn_generator(box, id, fcm, width);
625                                 break;
626                                 
627                         case FMODIFIER_TYPE_CYCLES: /* Cycles */
628                                 draw_modifier__cycles(box, id, fcm, width);
629                                 break;
630                                 
631                         case FMODIFIER_TYPE_ENVELOPE: /* Envelope */
632                                 draw_modifier__envelope(box, id, fcm, width);
633                                 break;
634                                 
635                         case FMODIFIER_TYPE_LIMITS: /* Limits */
636                                 draw_modifier__limits(box, id, fcm, width);
637                                 break;
638                         
639                         case FMODIFIER_TYPE_NOISE: /* Noise */
640                                 draw_modifier__noise(box, id, fcm, width);
641                                 break;
642                                 
643                         case FMODIFIER_TYPE_STEPPED: /* Stepped */
644                                 draw_modifier__stepped(box, id, fcm, width);
645                                 break;
646                         
647                         default: /* unknown type */
648                                 break;
649                 }
650                 
651                 /* one last panel below this: FModifier range */
652                 // TODO: experiment with placement of this
653                 {
654                         box = uiLayoutBox(layout);
655                         
656                         /* restricted range ----------------------------------------------------- */
657                         col = uiLayoutColumn(box, true);
658                         
659                         /* top row: use restricted range */
660                         row = uiLayoutRow(col, true);
661                         uiItemR(row, &ptr, "use_restricted_range", 0, NULL, ICON_NONE);
662                         
663                         if (fcm->flag & FMODIFIER_FLAG_RANGERESTRICT) {
664                                 /* second row: settings */
665                                 row = uiLayoutRow(col, true);
666                                 
667                                 uiItemR(row, &ptr, "frame_start", 0, IFACE_("Start"), ICON_NONE);
668                                 uiItemR(row, &ptr, "frame_end", 0, IFACE_("End"), ICON_NONE);
669                                 
670                                 /* third row: blending influence */
671                                 row = uiLayoutRow(col, true);
672                                 
673                                 uiItemR(row, &ptr, "blend_in", 0, IFACE_("In"), ICON_NONE);
674                                 uiItemR(row, &ptr, "blend_out", 0, IFACE_("Out"), ICON_NONE);
675                         }
676                         
677                         /* influence -------------------------------------------------------------- */
678                         col = uiLayoutColumn(box, true);
679                         
680                         /* top row: use influence */
681                         uiItemR(col, &ptr, "use_influence", 0, NULL, ICON_NONE);
682                         
683                         if (fcm->flag & FMODIFIER_FLAG_USEINFLUENCE) {
684                                 /* second row: influence value */
685                                 uiItemR(col, &ptr, "influence", 0, NULL, ICON_NONE);
686                         }
687                 }
688         }
689 }
690
691 /* ********************************************** */
692 /* COPY/PASTE BUFFER STUFF */
693
694 /* Copy/Paste Buffer itself (list of FModifier 's) */
695 static ListBase fmodifier_copypaste_buf = {NULL, NULL};
696
697 /* ---------- */
698
699 /* free the copy/paste buffer */
700 void ANIM_fmodifiers_copybuf_free(void)
701 {
702         /* just free the whole buffer */
703         free_fmodifiers(&fmodifier_copypaste_buf);
704 }
705
706 /* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
707  * assuming that the buffer has been cleared already with ANIM_fmodifiers_copybuf_free()
708  *      - active: only copy the active modifier
709  */
710 bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
711 {
712         bool ok = true;
713         
714         /* sanity checks */
715         if (ELEM(NULL, modifiers, modifiers->first))
716                 return 0;
717                 
718         /* copy the whole list, or just the active one? */
719         if (active) {
720                 FModifier *fcm = find_active_fmodifier(modifiers);
721                 
722                 if (fcm) {
723                         FModifier *fcmN = copy_fmodifier(fcm);
724                         BLI_addtail(&fmodifier_copypaste_buf, fcmN);
725                 }
726                 else
727                         ok = 0;
728         }
729         else
730                 copy_fmodifiers(&fmodifier_copypaste_buf, modifiers);
731                 
732         /* did we succeed? */
733         return ok;
734 }
735
736 /* 'Paste' the F-Modifier(s) from the buffer to the specified list 
737  *      - replace: free all the existing modifiers to leave only the pasted ones 
738  */
739 bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace)
740 {
741         FModifier *fcm;
742         bool ok = false;
743         
744         /* sanity checks */
745         if (modifiers == NULL)
746                 return 0;
747                 
748         /* if replacing the list, free the existing modifiers */
749         if (replace)
750                 free_fmodifiers(modifiers);
751                 
752         /* now copy over all the modifiers in the buffer to the end of the list */
753         for (fcm = fmodifier_copypaste_buf.first; fcm; fcm = fcm->next) {
754                 /* make a copy of it */
755                 FModifier *fcmN = copy_fmodifier(fcm);
756                 
757                 /* make sure the new one isn't active, otherwise the list may get several actives */
758                 fcmN->flag &= ~FMODIFIER_FLAG_ACTIVE;
759                 
760                 /* now add it to the end of the list */
761                 BLI_addtail(modifiers, fcmN);
762                 ok = 1;
763         }
764         
765         /* did we succeed? */
766         return ok;
767 }
768
769 /* ********************************************** */