Blender  V2.59
fmodifier_ui.c
Go to the documentation of this file.
00001 /*
00002  * $Id: fmodifier_ui.c 36028 2011-04-06 01:13:01Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2009 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * 
00024  * Contributor(s): Blender Foundation, Joshua Leung
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 /* User-Interface Stuff for F-Modifiers:
00035  * This file defines the (C-Coded) templates + editing callbacks needed 
00036  * by the interface stuff or F-Modifiers, as used by F-Curves in the Graph Editor,
00037  * and NLA-Strips in the NLA Editor.
00038  *
00039  * Copy/Paste Buffer for F-Modifiers:
00040  * For now, this is also defined in this file so that it can be shared between the 
00041  */
00042  
00043 #include <string.h>
00044 
00045 #include "DNA_anim_types.h"
00046 #include "DNA_scene_types.h"
00047 
00048 #include "MEM_guardedalloc.h"
00049 
00050 #include "BLI_blenlib.h"
00051 #include "BLI_utildefines.h"
00052 
00053 #include "BKE_context.h"
00054 #include "BKE_fcurve.h"
00055 
00056 #include "WM_api.h"
00057 #include "WM_types.h"
00058 
00059 #include "RNA_access.h"
00060 
00061 #include "UI_interface.h"
00062 #include "UI_resources.h"
00063 
00064 #include "ED_anim_api.h"
00065 #include "ED_util.h"
00066 
00067 /* ********************************************** */
00068 /* UI STUFF */
00069 
00070 // XXX! --------------------------------
00071 /* temporary definition for limits of float number buttons (FLT_MAX tends to infinity with old system) */
00072 #define UI_FLT_MAX      10000.0f
00073 
00074 #define B_REDR                                  1
00075 #define B_FMODIFIER_REDRAW              20
00076 
00077 /* macro for use here to draw background box and set height */
00078 // XXX for now, roundbox has it's callback func set to NULL to not intercept events
00079 #define DRAW_BACKDROP(height) \
00080         { \
00081                 uiDefBut(block, ROUNDBOX, B_REDR, "", -3, yco-height, width+3, height-1, NULL, 5.0, 0.0, 12.0, (float)rb_col, ""); \
00082         }
00083 
00084 /* callback to verify modifier data */
00085 static void validate_fmodifier_cb (bContext *UNUSED(C), void *fcm_v, void *UNUSED(arg))
00086 {
00087         FModifier *fcm= (FModifier *)fcm_v;
00088         FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
00089         
00090         /* call the verify callback on the modifier if applicable */
00091         if (fmi && fmi->verify_data)
00092                 fmi->verify_data(fcm);
00093 }
00094 
00095 /* callback to remove the given modifier  */
00096 static void delete_fmodifier_cb (bContext *C, void *fmods_v, void *fcm_v)
00097 {
00098         ListBase *modifiers = (ListBase *)fmods_v;
00099         FModifier *fcm= (FModifier *)fcm_v;
00100         
00101         /* remove the given F-Modifier from the active modifier-stack */
00102         remove_fmodifier(modifiers, fcm);
00103 
00104         ED_undo_push(C, "Delete F-Curve Modifier");
00105         
00106         /* send notifiers */
00107         // 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 
00108         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
00109 }
00110 
00111 /* --------------- */
00112         
00113 /* draw settings for generator modifier */
00114 static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, short width)
00115 {
00116         FMod_Generator *data= (FMod_Generator *)fcm->data;
00117         uiLayout *col, *row;
00118         uiBlock *block;
00119         uiBut *but;
00120         PointerRNA ptr;
00121         
00122         /* init the RNA-pointer */
00123         RNA_pointer_create(id, &RNA_FModifierFunctionGenerator, fcm, &ptr);
00124         
00125         /* basic settings (backdrop + mode selector + some padding) */
00126         col= uiLayoutColumn(layout, 1);
00127         block= uiLayoutGetBlock(layout);
00128         uiBlockBeginAlign(block);
00129                 but= uiDefButR(block, MENU, B_FMODIFIER_REDRAW, NULL, 0, 0, width-30, UI_UNIT_Y, &ptr, "mode", -1, 0, 0, -1, -1, NULL);
00130                 uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
00131                 
00132                 uiDefButR(block, TOG, B_FMODIFIER_REDRAW, NULL, 0, 0, width-30, UI_UNIT_Y, &ptr, "use_additive", -1, 0, 0, -1, -1, NULL);
00133         uiBlockEndAlign(block);
00134         
00135         /* now add settings for individual modes */
00136         switch (data->mode) {
00137                 case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
00138                 {
00139                         float *cp = NULL;
00140                         char xval[32];
00141                         unsigned int i;
00142                         
00143                         /* draw polynomial order selector */
00144                         row= uiLayoutRow(layout, 0);
00145                         block= uiLayoutGetBlock(row);
00146                                 but= uiDefButI(block, NUM, B_FMODIFIER_REDRAW, "Poly Order: ", 10,0,width-30,19, &data->poly_order, 1, 100, 0, 0, "'Order' of the Polynomial - for a polynomial with n terms, 'order' is n-1");
00147                                 uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
00148                         
00149                         
00150                         /* draw controls for each coefficient and a + sign at end of row */
00151                         row= uiLayoutRow(layout, 1);
00152                         block= uiLayoutGetBlock(row);
00153                                 uiDefBut(block, LABEL, 1, "y = ", 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
00154                         
00155                         cp= data->coefficients;
00156                         for (i=0; (i < data->arraysize) && (cp); i++, cp++) {
00157                                 /* coefficient */
00158                                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 150, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient for polynomial");
00159                                 
00160                                 /* 'x' param (and '+' if necessary) */
00161                                 if (i) {
00162                                         if (i == 1)
00163                                                 strcpy(xval, "x");
00164                                         else
00165                                                 sprintf(xval, "x^%d", i);
00166                                         uiDefBut(block, LABEL, 1, xval, 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, "Power of x");
00167                                 }
00168                                 
00169                                 if ( (i != (data->arraysize - 1)) || ((i==0) && data->arraysize==2) ) {
00170                                         uiDefBut(block, LABEL, 1, "+", 0,0 , 30, 20, NULL, 0.0, 0.0, 0, 0, "");
00171                                         
00172                                         /* next coefficient on a new row */
00173                                         row= uiLayoutRow(layout, 1);
00174                                         block= uiLayoutGetBlock(row);
00175                                 }
00176                         }
00177                 }
00178                         break;
00179                 
00180                 case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial expression */
00181                 {
00182                         float *cp = NULL;
00183                         unsigned int i;
00184                         
00185                         /* draw polynomial order selector */
00186                         row= uiLayoutRow(layout, 0);
00187                         block= uiLayoutGetBlock(row);
00188                                 but= uiDefButI(block, NUM, B_FMODIFIER_REDRAW, "Poly Order: ", 0,0,width-30,19, &data->poly_order, 1, 100, 0, 0, "'Order' of the Polynomial - for a polynomial with n terms, 'order' is n-1");
00189                                 uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
00190                         
00191                         
00192                         /* draw controls for each pair of coefficients */
00193                         row= uiLayoutRow(layout, 1);
00194                         block= uiLayoutGetBlock(row);
00195                                 uiDefBut(block, LABEL, 1, "y=", 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
00196                         
00197                         cp= data->coefficients;
00198                         for (i=0; (i < data->poly_order) && (cp); i++, cp+=2) {
00199                                 /* opening bracket */
00200                                 uiDefBut(block, LABEL, 1, "(", 0, 0, 20, 20, NULL, 0.0, 0.0, 0, 0, "");
00201                                 
00202                                 /* coefficients */
00203                                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 100, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient of x");
00204                                 
00205                                 uiDefBut(block, LABEL, 1, "x+", 0, 0, 40, 20, NULL, 0.0, 0.0, 0, 0, "");
00206                                 
00207                                 uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 100, 20, cp+1, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Second coefficient");
00208                                 
00209                                 /* closing bracket and '+' sign */
00210                                 if ( (i != (data->poly_order - 1)) || ((i==0) && data->poly_order==2) ) {
00211                                         uiDefBut(block, LABEL, 1, ") +", 0, 0, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
00212                                         
00213                                         /* set up new row for the next pair of coefficients*/
00214                                         row= uiLayoutRow(layout, 1);
00215                                         block= uiLayoutGetBlock(row);
00216                                 }
00217                                 else 
00218                                         uiDefBut(block, LABEL, 1, ")", 0, 0, 20, 20, NULL, 0.0, 0.0, 0, 0, "");
00219                         }
00220                 }
00221                         break;
00222         }
00223 }
00224 
00225 /* --------------- */
00226 
00227 /* draw settings for generator modifier */
00228 static void draw_modifier__fn_generator(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
00229 {
00230         uiLayout *col;
00231         PointerRNA ptr;
00232         
00233         /* init the RNA-pointer */
00234         RNA_pointer_create(id, &RNA_FModifierFunctionGenerator, fcm, &ptr);
00235         
00236         /* add the settings */
00237         col= uiLayoutColumn(layout, 1);
00238                 uiItemR(col, &ptr, "function_type", 0, "", ICON_NONE);
00239                 uiItemR(col, &ptr, "use_additive", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
00240         
00241         col= uiLayoutColumn(layout, 0); // no grouping for now
00242                 uiItemR(col, &ptr, "amplitude", 0, NULL, ICON_NONE);
00243                 uiItemR(col, &ptr, "phase_multiplier", 0, NULL, ICON_NONE);
00244                 uiItemR(col, &ptr, "phase_offset", 0, NULL, ICON_NONE);
00245                 uiItemR(col, &ptr, "value_offset", 0, NULL, ICON_NONE);
00246 }
00247 
00248 /* --------------- */
00249 
00250 /* draw settings for cycles modifier */
00251 static void draw_modifier__cycles(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
00252 {
00253         uiLayout *split, *col;
00254         PointerRNA ptr;
00255         
00256         /* init the RNA-pointer */
00257         RNA_pointer_create(id, &RNA_FModifierCycles, fcm, &ptr);
00258         
00259         /* split into 2 columns 
00260          * NOTE: the mode comboboxes shouldn't get labels, otherwise there isn't enough room
00261          */
00262         split= uiLayoutSplit(layout, 0.5f, 0);
00263         
00264         /* before range */
00265         col= uiLayoutColumn(split, 1);
00266                 uiItemL(col, "Before:", ICON_NONE);
00267                 uiItemR(col, &ptr, "mode_before", 0, "", ICON_NONE);
00268                 uiItemR(col, &ptr, "cycles_before", 0, NULL, ICON_NONE);
00269                 
00270         /* after range */
00271         col= uiLayoutColumn(split, 1);
00272                 uiItemL(col, "After:", ICON_NONE);
00273                 uiItemR(col, &ptr, "mode_after", 0, "", ICON_NONE);
00274                 uiItemR(col, &ptr, "cycles_after", 0, NULL, ICON_NONE);
00275 }
00276 
00277 /* --------------- */
00278 
00279 /* draw settings for noise modifier */
00280 static void draw_modifier__noise(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
00281 {
00282         uiLayout *split, *col;
00283         PointerRNA ptr;
00284         
00285         /* init the RNA-pointer */
00286         RNA_pointer_create(id, &RNA_FModifierNoise, fcm, &ptr);
00287         
00288         /* blending mode */
00289         uiItemR(layout, &ptr, "blend_type", 0, NULL, ICON_NONE);
00290         
00291         /* split into 2 columns */
00292         split= uiLayoutSplit(layout, 0.5f, 0);
00293         
00294         /* col 1 */
00295         col= uiLayoutColumn(split, 0);
00296                 uiItemR(col, &ptr, "scale", 0, NULL, ICON_NONE);
00297                 uiItemR(col, &ptr, "strength", 0, NULL, ICON_NONE);
00298         
00299         /* col 2 */
00300         col= uiLayoutColumn(split, 0);
00301                 uiItemR(col, &ptr, "phase", 0, NULL, ICON_NONE);
00302                 uiItemR(col, &ptr, "depth", 0, NULL, ICON_NONE);
00303 }
00304 
00305 /* --------------- */
00306 
00307 #define BINARYSEARCH_FRAMEEQ_THRESH     0.0001f
00308 
00309 /* Binary search algorithm for finding where to insert Envelope Data Point.
00310  * Returns the index to insert at (data already at that index will be offset if replace is 0)
00311  */
00312 static int binarysearch_fcm_envelopedata_index (FCM_EnvelopeData array[], float frame, int arraylen, short *exists)
00313 {
00314         int start=0, end=arraylen;
00315         int loopbreaker= 0, maxloop= arraylen * 2;
00316         
00317         /* initialise exists-flag first */
00318         *exists= 0;
00319         
00320         /* sneaky optimisations (don't go through searching process if...):
00321          *      - keyframe to be added is to be added out of current bounds
00322          *      - keyframe to be added would replace one of the existing ones on bounds
00323          */
00324         if ((arraylen <= 0) || (array == NULL)) {
00325                 printf("Warning: binarysearch_fcm_envelopedata_index() encountered invalid array \n");
00326                 return 0;
00327         }
00328         else {
00329                 /* check whether to add before/after/on */
00330                 float framenum;
00331                 
00332                 /* 'First' Point (when only one point, this case is used) */
00333                 framenum= array[0].time;
00334                 if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
00335                         *exists = 1;
00336                         return 0;
00337                 }
00338                 else if (frame < framenum)
00339                         return 0;
00340                         
00341                 /* 'Last' Point */
00342                 framenum= array[(arraylen-1)].time;
00343                 if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
00344                         *exists= 1;
00345                         return (arraylen - 1);
00346                 }
00347                 else if (frame > framenum)
00348                         return arraylen;
00349         }
00350         
00351         
00352         /* most of the time, this loop is just to find where to put it
00353          *      - 'loopbreaker' is just here to prevent infinite loops 
00354          */
00355         for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
00356                 /* compute and get midpoint */
00357                 int mid = start + ((end - start) / 2);  /* we calculate the midpoint this way to avoid int overflows... */
00358                 float midfra= array[mid].time;
00359                 
00360                 /* check if exactly equal to midpoint */
00361                 if (IS_EQT(frame, midfra, BINARYSEARCH_FRAMEEQ_THRESH)) {
00362                         *exists = 1;
00363                         return mid;
00364                 }
00365                 
00366                 /* repeat in upper/lower half */
00367                 if (frame > midfra)
00368                         start= mid + 1;
00369                 else if (frame < midfra)
00370                         end= mid - 1;
00371         }
00372         
00373         /* print error if loop-limit exceeded */
00374         if (loopbreaker == (maxloop-1)) {
00375                 printf("Error: binarysearch_fcm_envelopedata_index() was taking too long \n");
00376                 
00377                 // include debug info 
00378                 printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
00379         }
00380         
00381         /* not found, so return where to place it */
00382         return start;
00383 }
00384 
00385 /* callback to add new envelope data point */
00386 // TODO: should we have a separate file for things like this?
00387 static void fmod_envelope_addpoint_cb (bContext *C, void *fcm_dv, void *UNUSED(arg))
00388 {
00389         Scene *scene= CTX_data_scene(C);
00390         FMod_Envelope *env= (FMod_Envelope *)fcm_dv;
00391         FCM_EnvelopeData *fedn;
00392         FCM_EnvelopeData fed;
00393         
00394         /* init template data */
00395         fed.min= -1.0f;
00396         fed.max= 1.0f;
00397         fed.time= (float)scene->r.cfra; // XXX make this int for ease of use?
00398         fed.f1= fed.f2= 0;
00399         
00400         /* check that no data exists for the current frame... */
00401         if (env->data) {
00402                 short exists = -1;
00403                 int i= binarysearch_fcm_envelopedata_index(env->data, (float)(scene->r.cfra), env->totvert, &exists);
00404                 
00405                 /* binarysearch_...() will set exists by default to 0, so if it is non-zero, that means that the point exists already */
00406                 if (exists)
00407                         return;
00408                         
00409                 /* add new */
00410                 fedn= MEM_callocN((env->totvert+1)*sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
00411                 
00412                 /* add the points that should occur before the point to be pasted */
00413                 if (i > 0)
00414                         memcpy(fedn, env->data, i*sizeof(FCM_EnvelopeData));
00415                 
00416                 /* add point to paste at index i */
00417                 *(fedn + i)= fed;
00418                 
00419                 /* add the points that occur after the point to be pasted */
00420                 if (i < env->totvert) 
00421                         memcpy(fedn+i+1, env->data+i, (env->totvert-i)*sizeof(FCM_EnvelopeData));
00422                 
00423                 /* replace (+ free) old with new */
00424                 MEM_freeN(env->data);
00425                 env->data= fedn;
00426                 
00427                 env->totvert++;
00428         }
00429         else {
00430                 env->data= MEM_callocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
00431                 *(env->data)= fed;
00432                 
00433                 env->totvert= 1;
00434         }
00435 }
00436 
00437 /* callback to remove envelope data point */
00438 // TODO: should we have a separate file for things like this?
00439 static void fmod_envelope_deletepoint_cb (bContext *UNUSED(C), void *fcm_dv, void *ind_v)
00440 {
00441         FMod_Envelope *env= (FMod_Envelope *)fcm_dv;
00442         FCM_EnvelopeData *fedn;
00443         int index= GET_INT_FROM_POINTER(ind_v);
00444         
00445         /* check that no data exists for the current frame... */
00446         if (env->totvert > 1) {
00447                 /* allocate a new smaller array */
00448                 fedn= MEM_callocN(sizeof(FCM_EnvelopeData)*(env->totvert-1), "FCM_EnvelopeData");
00449 
00450                 memcpy(fedn, env->data, sizeof(FCM_EnvelopeData)*(index));
00451                 memcpy(fedn + index, env->data + (index + 1), sizeof(FCM_EnvelopeData)*((env->totvert - index)-1));
00452                 
00453                 /* free old array, and set the new */
00454                 MEM_freeN(env->data);
00455                 env->data= fedn;
00456                 env->totvert--;
00457         }
00458         else {
00459                 /* just free array, since the only vert was deleted */
00460                 if (env->data) {
00461                         MEM_freeN(env->data);
00462                         env->data= NULL;
00463                 }
00464                 env->totvert= 0;
00465         }
00466 }
00467 
00468 /* draw settings for envelope modifier */
00469 static void draw_modifier__envelope(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
00470 {
00471         FMod_Envelope *env= (FMod_Envelope *)fcm->data;
00472         FCM_EnvelopeData *fed;
00473         uiLayout *col, *row;
00474         uiBlock *block;
00475         uiBut *but;
00476         PointerRNA ptr;
00477         int i;
00478         
00479         /* init the RNA-pointer */
00480         RNA_pointer_create(id, &RNA_FModifierEnvelope, fcm, &ptr);
00481         
00482         /* general settings */
00483         col= uiLayoutColumn(layout, 1);
00484                 uiItemL(col, "Envelope:", ICON_NONE);
00485                 uiItemR(col, &ptr, "reference_value", 0, NULL, ICON_NONE);
00486                 
00487                 row= uiLayoutRow(col, 1);
00488                         uiItemR(row, &ptr, "default_min", 0, "Min", ICON_NONE);
00489                         uiItemR(row, &ptr, "default_max", 0, "Max", ICON_NONE);
00490                         
00491         /* control points header */
00492         // TODO: move this control-point control stuff to using the new special widgets for lists
00493         // the current way is far too cramped
00494         row= uiLayoutRow(layout, 0);
00495         block= uiLayoutGetBlock(row);
00496                 
00497                 uiDefBut(block, LABEL, 1, "Control Points:", 0, 0, 150, 20, NULL, 0.0, 0.0, 0, 0, "");
00498                 
00499                 but= uiDefBut(block, BUT, B_FMODIFIER_REDRAW, "Add Point", 0,0,150,19, NULL, 0, 0, 0, 0, "Adds a new control-point to the envelope on the current frame");
00500                 uiButSetFunc(but, fmod_envelope_addpoint_cb, env, NULL);
00501                 
00502         /* control points list */
00503         for (i=0, fed=env->data; i < env->totvert; i++, fed++) {
00504                 /* get a new row to operate on */
00505                 row= uiLayoutRow(layout, 1);
00506                 block= uiLayoutGetBlock(row);
00507                 
00508                 uiBlockBeginAlign(block);
00509                         but=uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Fra:", 0, 0, 90, 20, &fed->time, -MAXFRAMEF, MAXFRAMEF, 10, 1, "Frame that envelope point occurs");
00510                         uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
00511                         
00512                         uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Min:", 0, 0, 100, 20, &fed->min, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, "Minimum bound of envelope at this point");
00513                         uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Max:", 0, 0, 100, 20, &fed->max, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, "Maximum bound of envelope at this point");
00514                         
00515                         but= uiDefIconBut(block, BUT, B_FMODIFIER_REDRAW, ICON_X, 0, 0, 18, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Delete envelope control point");
00516                         uiButSetFunc(but, fmod_envelope_deletepoint_cb, env, SET_INT_IN_POINTER(i));
00517                 uiBlockBeginAlign(block);
00518         }
00519 }
00520 
00521 /* --------------- */
00522 
00523 /* draw settings for limits modifier */
00524 static void draw_modifier__limits(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
00525 {
00526         uiLayout *split, *col, *row;
00527         PointerRNA ptr;
00528         
00529         /* init the RNA-pointer */
00530         RNA_pointer_create(id, &RNA_FModifierLimits, fcm, &ptr);
00531         
00532         /* row 1: minimum */
00533         {
00534                 row= uiLayoutRow(layout, 0);
00535                 
00536                 /* split into 2 columns */
00537                 split= uiLayoutSplit(layout, 0.5f, 0);
00538                 
00539                 /* x-minimum */
00540                 col= uiLayoutColumn(split, 1);
00541                         uiItemR(col, &ptr, "use_min_x", 0, NULL, ICON_NONE);
00542                         uiItemR(col, &ptr, "min_x", 0, NULL, ICON_NONE);
00543                         
00544                 /* y-minimum*/
00545                 col= uiLayoutColumn(split, 1);
00546                         uiItemR(col, &ptr, "use_min_y", 0, NULL, ICON_NONE);
00547                         uiItemR(col, &ptr, "min_y", 0, NULL, ICON_NONE);
00548         }
00549         
00550         /* row 2: maximum */
00551         {
00552                 row= uiLayoutRow(layout, 0);
00553                 
00554                 /* split into 2 columns */
00555                 split= uiLayoutSplit(layout, 0.5f, 0);
00556                 
00557                 /* x-minimum */
00558                 col= uiLayoutColumn(split, 1);
00559                         uiItemR(col, &ptr, "use_max_x", 0, NULL, ICON_NONE);
00560                         uiItemR(col, &ptr, "max_x", 0, NULL, ICON_NONE);
00561                         
00562                 /* y-minimum*/
00563                 col= uiLayoutColumn(split, 1);
00564                         uiItemR(col, &ptr, "use_max_y", 0, NULL, ICON_NONE);
00565                         uiItemR(col, &ptr, "max_y", 0, NULL, ICON_NONE);
00566         }
00567 }
00568 
00569 /* --------------- */
00570 
00571 /* draw settings for stepped interpolation modifier */
00572 static void draw_modifier__stepped(uiLayout *layout, ID *id, FModifier *fcm, short UNUSED(width))
00573 {
00574         uiLayout *col, *subcol;
00575         PointerRNA ptr;
00576         
00577         /* init the RNA-pointer */
00578         RNA_pointer_create(id, &RNA_FModifierStepped, fcm, &ptr);
00579         
00580         /* block 1: "stepping" settings */
00581         col= uiLayoutColumn(layout, 0);
00582                 uiItemR(col, &ptr, "frame_step", 0, NULL, ICON_NONE);
00583                 uiItemR(col, &ptr, "frame_offset", 0, NULL, ICON_NONE);
00584                 
00585         /* block 2: start range settings */
00586         col= uiLayoutColumn(layout, 1);
00587                 uiItemR(col, &ptr, "use_frame_start", 0, NULL, ICON_NONE);
00588                 
00589                 subcol = uiLayoutColumn(col, 1);
00590                 uiLayoutSetActive(subcol, RNA_boolean_get(&ptr, "use_frame_start"));
00591                         uiItemR(subcol, &ptr, "frame_start", 0, NULL, ICON_NONE);
00592                         
00593         /* block 3: end range settings */
00594         col= uiLayoutColumn(layout, 1);
00595                 uiItemR(col, &ptr, "use_frame_end", 0, NULL, ICON_NONE);
00596                 
00597                 subcol = uiLayoutColumn(col, 1);
00598                 uiLayoutSetActive(subcol, RNA_boolean_get(&ptr, "use_frame_end"));
00599                         uiItemR(subcol, &ptr, "frame_end", 0, NULL, ICON_NONE);
00600 }
00601 
00602 /* --------------- */
00603 
00604 void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm)
00605 {
00606         FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
00607         uiLayout *box, *row, *subrow;
00608         uiBlock *block;
00609         uiBut *but;
00610         short width= 314;
00611         PointerRNA ptr;
00612         
00613         /* init the RNA-pointer */
00614         RNA_pointer_create(id, &RNA_FModifier, fcm, &ptr);
00615         
00616         /* draw header */
00617         {
00618                 /* get layout-row + UI-block for this */
00619                 box= uiLayoutBox(layout);
00620                 
00621                 row= uiLayoutRow(box, 0);
00622                 block= uiLayoutGetBlock(row); // err...
00623                 
00624                 /* left-align -------------------------------------------- */
00625                 subrow= uiLayoutRow(row, 0);
00626                 uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_LEFT);
00627                 
00628                 uiBlockSetEmboss(block, UI_EMBOSSN);
00629                 
00630                 /* expand */
00631                 uiItemR(subrow, &ptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
00632                 
00633                 /* checkbox for 'active' status (for now) */
00634                 uiItemR(subrow, &ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
00635                 
00636                 /* name */
00637                 if (fmi)
00638                         uiItemL(subrow, fmi->name, ICON_NONE);
00639                 else
00640                         uiItemL(subrow, "<Unknown Modifier>", ICON_NONE);
00641                 
00642                 /* right-align ------------------------------------------- */
00643                 subrow= uiLayoutRow(row, 0);
00644                 uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT);
00645                 
00646                 
00647                 /* 'mute' button */
00648                 uiItemR(subrow, &ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
00649                 
00650                 uiBlockSetEmboss(block, UI_EMBOSSN);
00651                 
00652                 /* delete button */
00653                 but= uiDefIconBut(block, BUT, B_REDR, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Delete F-Curve Modifier.");
00654                 uiButSetFunc(but, delete_fmodifier_cb, modifiers, fcm);
00655                 
00656                 uiBlockSetEmboss(block, UI_EMBOSS);
00657         }
00658         
00659         /* when modifier is expanded, draw settings */
00660         if (fcm->flag & FMODIFIER_FLAG_EXPANDED) {
00661                 /* set up the flexible-box layout which acts as the backdrop for the modifier settings */
00662                 box= uiLayoutBox(layout); 
00663                 
00664                 /* draw settings for individual modifiers */
00665                 switch (fcm->type) {
00666                         case FMODIFIER_TYPE_GENERATOR: /* Generator */
00667                                 draw_modifier__generator(box, id, fcm, width);
00668                                 break;
00669                                 
00670                         case FMODIFIER_TYPE_FN_GENERATOR: /* Built-In Function Generator */
00671                                 draw_modifier__fn_generator(box, id, fcm, width);
00672                                 break;
00673                                 
00674                         case FMODIFIER_TYPE_CYCLES: /* Cycles */
00675                                 draw_modifier__cycles(box, id, fcm, width);
00676                                 break;
00677                                 
00678                         case FMODIFIER_TYPE_ENVELOPE: /* Envelope */
00679                                 draw_modifier__envelope(box, id, fcm, width);
00680                                 break;
00681                                 
00682                         case FMODIFIER_TYPE_LIMITS: /* Limits */
00683                                 draw_modifier__limits(box, id, fcm, width);
00684                                 break;
00685                         
00686                         case FMODIFIER_TYPE_NOISE: /* Noise */
00687                                 draw_modifier__noise(box, id, fcm, width);
00688                                 break;
00689                                 
00690                         case FMODIFIER_TYPE_STEPPED: /* Stepped */
00691                                 draw_modifier__stepped(box, id, fcm, width);
00692                                 break;
00693                         
00694                         default: /* unknown type */
00695                                 break;
00696                 }
00697         }
00698 }
00699 
00700 /* ********************************************** */
00701 /* COPY/PASTE BUFFER STUFF */
00702 
00703 /* Copy/Paste Buffer itself (list of FModifier 's) */
00704 static ListBase fmodifier_copypaste_buf = {NULL, NULL};
00705 
00706 /* ---------- */
00707 
00708 /* free the copy/paste buffer */
00709 void free_fmodifiers_copybuf (void)
00710 {
00711         /* just free the whole buffer */
00712         free_fmodifiers(&fmodifier_copypaste_buf);
00713 }
00714 
00715 /* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
00716  * assuming that the buffer has been cleared already with free_fmodifiers_copybuf()
00717  *      - active: only copy the active modifier
00718  */
00719 short ANIM_fmodifiers_copy_to_buf (ListBase *modifiers, short active)
00720 {
00721         short ok = 1;
00722         
00723         /* sanity checks */
00724         if ELEM(NULL, modifiers, modifiers->first)
00725                 return 0;
00726                 
00727         /* copy the whole list, or just the active one? */
00728         if (active) {
00729                 FModifier *fcm = find_active_fmodifier(modifiers);
00730                 
00731                 if (fcm) {
00732                         FModifier *fcmN = copy_fmodifier(fcm);
00733                         BLI_addtail(&fmodifier_copypaste_buf, fcmN);
00734                 }
00735                 else
00736                         ok = 0;
00737         }
00738         else
00739                 copy_fmodifiers(&fmodifier_copypaste_buf, modifiers);
00740                 
00741         /* did we succeed? */
00742         return ok;
00743 }
00744 
00745 /* 'Paste' the F-Modifier(s) from the buffer to the specified list 
00746  *      - replace: free all the existing modifiers to leave only the pasted ones 
00747  */
00748 short ANIM_fmodifiers_paste_from_buf (ListBase *modifiers, short replace)
00749 {
00750         FModifier *fcm;
00751         short ok = 0;
00752         
00753         /* sanity checks */
00754         if (modifiers == NULL)
00755                 return 0;
00756                 
00757         /* if replacing the list, free the existing modifiers */
00758         if (replace)
00759                 free_fmodifiers(modifiers);
00760                 
00761         /* now copy over all the modifiers in the buffer to the end of the list */
00762         for (fcm= fmodifier_copypaste_buf.first; fcm; fcm= fcm->next) {
00763                 /* make a copy of it */
00764                 FModifier *fcmN = copy_fmodifier(fcm);
00765                 
00766                 /* make sure the new one isn't active, otherwise the list may get several actives */
00767                 fcmN->flag &= ~FMODIFIER_FLAG_ACTIVE;
00768                 
00769                 /* now add it to the end of the list */
00770                 BLI_addtail(modifiers, fcmN);
00771                 ok = 1;
00772         }
00773         
00774         /* did we succeed? */
00775         return ok;
00776 }
00777 
00778 /* ********************************************** */