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