changes to defaults for sequencer strip adding
[blender.git] / source / blender / editors / space_sequencer / sequencer_add.c
1 /**
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * Contributor(s): Blender Foundation, 2003-2009, Campbell Barton
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include <stdlib.h>
28 #include <math.h>
29 #include <string.h>
30
31 #ifndef WIN32
32 #include <unistd.h>
33 #else
34 #include <io.h>
35 #endif
36 #include <sys/types.h>
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BLI_blenlib.h"
41 #include "BLI_arithb.h"
42 #include "BLI_storage_types.h"
43
44 #include "IMB_imbuf_types.h"
45 #include "IMB_imbuf.h"
46
47 #include "DNA_ipo_types.h"
48 #include "DNA_curve_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_space_types.h"
52 #include "DNA_sequence_types.h"
53 #include "DNA_view2d_types.h"
54 #include "DNA_userdef_types.h"
55 #include "DNA_sound_types.h"
56
57 #include "BKE_context.h"
58 #include "BKE_global.h"
59 #include "BKE_image.h"
60 #include "BKE_library.h"
61 #include "BKE_main.h"
62 #include "BKE_plugin_types.h"
63 #include "BKE_sequence.h"
64 #include "BKE_scene.h"
65 #include "BKE_utildefines.h"
66 #include "BKE_report.h"
67
68 #include "BIF_gl.h"
69 #include "BIF_glutil.h"
70
71 #include "WM_api.h"
72 #include "WM_types.h"
73
74 #include "RNA_access.h"
75 #include "RNA_define.h"
76
77 /* for menu/popup icons etc etc*/
78 #include "UI_interface.h"
79 #include "UI_resources.h"
80
81 #include "ED_anim_api.h"
82 #include "ED_space_api.h"
83 #include "ED_types.h"
84 #include "ED_screen.h"
85 #include "ED_util.h"
86 #include "ED_fileselect.h"
87
88 #include "UI_interface.h"
89 #include "UI_resources.h"
90 #include "UI_view2d.h"
91
92 /* own include */
93 #include "sequencer_intern.h"
94
95 /* Generic functions, reused by add strip operators */
96
97 /* avoid passing multiple args and be more verbose */
98 #define SEQPROP_STARTFRAME      1<<0
99 #define SEQPROP_ENDFRAME        1<<1
100
101 static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
102 {
103         RNA_def_string(ot->srna, "name", "", MAX_ID_NAME-2, "Name", "Name of the new sequence strip");
104
105         if(flag & SEQPROP_STARTFRAME)
106                 RNA_def_int(ot->srna, "start_frame", 0, INT_MIN, INT_MAX, "Start Frame", "Start frame of the sequence strip", INT_MIN, INT_MAX);
107         
108         if(flag & SEQPROP_ENDFRAME)
109                 RNA_def_int(ot->srna, "end_frame", 0, INT_MIN, INT_MAX, "End Frame", "End frame for the color strip", INT_MIN, INT_MAX); /* not useual since most strips have a fixed length */
110         
111         RNA_def_int(ot->srna, "channel", 1, 1, MAXSEQ, "Channel", "Channel to place this strip into", 1, MAXSEQ);
112         
113         RNA_def_boolean(ot->srna, "replace_sel", 1, "Replace Selection", "replace the current selection");
114 }
115
116 static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, wmEvent *event, int flag)
117 {
118         ARegion *ar= CTX_wm_region(C);
119         View2D *v2d= UI_view2d_fromcontext(C);
120         
121         short mval[2];  
122         float mval_v2d[2];
123         
124
125         mval[0]= event->x - ar->winrct.xmin;
126         mval[1]= event->y - ar->winrct.ymin;
127         
128         UI_view2d_region_to_view(v2d, mval[0], mval[1], &mval_v2d[0], &mval_v2d[1]);
129         
130         RNA_int_set(op->ptr, "channel", (int)mval_v2d[1]+0.5f);
131         RNA_int_set(op->ptr, "start_frame", (int)mval_v2d[0]);
132         
133         if ((flag & SEQPROP_ENDFRAME) && RNA_property_is_set(op->ptr, "end_frame")==0)
134                 RNA_int_set(op->ptr, "end_frame", (int)mval_v2d[0] + 25); // XXX arbitary but ok for now.
135         
136 }
137
138 /* add scene operator */
139 static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
140 {
141         Scene *scene= CTX_data_scene(C);
142         Editing *ed= seq_give_editing(scene, TRUE);
143         
144         Scene *sce_seq;
145         char sce_name[MAX_ID_NAME-2];
146         
147         Sequence *seq;  /* generic strip vars */
148         Strip *strip;
149         StripElem *se;
150         
151         int start_frame, channel; /* operator props */
152         
153         start_frame= RNA_int_get(op->ptr, "start_frame");
154         channel= RNA_int_get(op->ptr, "channel");
155         
156         RNA_string_get(op->ptr, "scene", sce_name);
157
158         sce_seq= (Scene *)find_id("SC", sce_name);
159         
160         if (sce_seq==NULL) {
161                 BKE_reportf(op->reports, RPT_ERROR, "Scene \"%s\" not found", sce_name);
162                 return OPERATOR_CANCELLED;
163         }
164         
165         seq = alloc_sequence(ed->seqbasep, start_frame, channel);
166         
167         seq->type= SEQ_SCENE;
168         seq->scene= sce_seq;
169         
170         /* basic defaults */
171         seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
172         strip->len = seq->len = sce_seq->r.efra - sce_seq->r.sfra + 1;
173         strip->us= 1;
174         
175         strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
176         
177         
178         RNA_string_get(op->ptr, "name", seq->name);
179         
180         calc_sequence_disp(seq);
181         sort_seq(scene);
182         
183         if (RNA_boolean_get(op->ptr, "replace_sel")) {
184                 deselect_all_seq(scene);
185                 set_last_seq(scene, seq);
186                 seq->flag |= SELECT;
187         }
188         
189         ED_area_tag_redraw(CTX_wm_area(C));
190         
191         return OPERATOR_FINISHED;
192 }
193
194
195 static int sequencer_add_scene_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
196 {
197         sequencer_generic_invoke_xy__internal(C, op, event, 0);
198         
199         /* scene can be left default */
200         RNA_string_set(op->ptr, "scene", "Scene"); // XXX should popup a menu but ton says 2.5 will have some better feature for this
201
202         return sequencer_add_scene_strip_exec(C, op);
203 }
204
205
206 void SEQUENCER_OT_scene_strip_add(struct wmOperatorType *ot)
207 {
208         
209         /* identifiers */
210         ot->name= "Add Scene Strip";
211         ot->idname= "SEQUENCER_OT_scene_strip_add";
212         ot->description= "Add a strip to the sequencer using a blender scene as a source";
213
214         /* api callbacks */
215         ot->invoke= sequencer_add_scene_strip_invoke;
216         ot->exec= sequencer_add_scene_strip_exec;
217
218         ot->poll= ED_operator_sequencer_active;
219         
220         /* flags */
221         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
222         
223         sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
224         RNA_def_string(ot->srna, "scene", "", MAX_ID_NAME-2, "Scene Name", "Scene name to add as a strip");
225 }
226
227 /* add movie operator */
228 static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
229 {
230         Scene *scene= CTX_data_scene(C);
231         Editing *ed= seq_give_editing(scene, TRUE);
232         
233         struct anim *an;
234         char filename[FILE_MAX];
235
236         Sequence *seq;  /* generic strip vars */
237         Strip *strip;
238         StripElem *se;
239         
240         int start_frame, channel; /* operator props */
241         
242         start_frame= RNA_int_get(op->ptr, "start_frame");
243         channel= RNA_int_get(op->ptr, "channel");
244         
245         RNA_string_get(op->ptr, "filename", filename);
246         
247         an = openanim(filename, IB_rect);
248
249         if (an==NULL) {
250                 BKE_reportf(op->reports, RPT_ERROR, "Filename \"%s\" could not be loaded as a movie", filename);
251                 return OPERATOR_CANCELLED;
252         }
253         
254         seq = alloc_sequence(ed->seqbasep, start_frame, channel);
255         
256         seq->type= SEQ_MOVIE;
257         seq->anim= an;
258         seq->anim_preseek = IMB_anim_get_preseek(an);
259         
260         /* basic defaults */
261         seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
262         strip->len = seq->len = IMB_anim_get_duration( an ); 
263         strip->us= 1;
264         
265         strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
266         
267         BLI_split_dirfile_basic(filename, strip->dir, se->name);
268
269         RNA_string_get(op->ptr, "name", seq->name);
270         
271         calc_sequence_disp(seq);
272         sort_seq(scene);
273
274         if (RNA_boolean_get(op->ptr, "replace_sel")) {
275                 deselect_all_seq(scene);
276                 set_last_seq(scene, seq);
277                 seq->flag |= SELECT;
278         }
279         
280         ED_area_tag_redraw(CTX_wm_area(C));
281         
282         return OPERATOR_FINISHED;
283 }
284
285
286 static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
287 {       
288         sequencer_generic_invoke_xy__internal(C, op, event, 0);
289         return WM_operator_filesel(C, op, event);
290         //return sequencer_add_movie_strip_exec(C, op);
291 }
292
293
294 void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
295 {
296         
297         /* identifiers */
298         ot->name= "Add Movie Strip";
299         ot->idname= "SEQUENCER_OT_movie_strip_add";
300         ot->description= "Add a movie strip to the sequencer";
301
302         /* api callbacks */
303         ot->invoke= sequencer_add_movie_strip_invoke;
304         ot->exec= sequencer_add_movie_strip_exec;
305
306         ot->poll= ED_operator_sequencer_active;
307         
308         /* flags */
309         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
310         
311         WM_operator_properties_filesel(ot, FOLDERFILE|MOVIEFILE);
312         sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
313         RNA_def_boolean(ot->srna, "sound", TRUE, "Sound", "Load hd sound with the movie"); // XXX need to impliment this
314 }
315
316
317 /* add sound operator */
318 static int sequencer_add_sound_strip_exec(bContext *C, wmOperator *op)
319 {
320         Scene *scene= CTX_data_scene(C);
321         Editing *ed= seq_give_editing(scene, TRUE);
322         
323         bSound *sound;
324
325         char filename[FILE_MAX];
326
327         Sequence *seq;  /* generic strip vars */
328         Strip *strip;
329         StripElem *se;
330         
331         int start_frame, channel; /* operator props */
332         
333         start_frame= RNA_int_get(op->ptr, "start_frame");
334         channel= RNA_int_get(op->ptr, "channel");
335         
336         RNA_string_get(op->ptr, "filename", filename);
337
338         /* XXX if(sfile->flag & FILE_STRINGCODE) {
339                 BLI_makestringcode(G.sce, str);
340         }*/
341
342 // XXX  sound= sound_new_sound(filename);
343         sound= NULL;
344
345         if (sound==NULL || sound->sample->type == SAMPLE_INVALID) {
346                 BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
347                 return OPERATOR_CANCELLED;
348         }
349
350         if (sound==NULL || sound->sample->bits != 16) {
351                 BKE_report(op->reports, RPT_ERROR, "Only 16 bit audio is supported");
352                 return OPERATOR_CANCELLED;
353         }
354         
355         sound->flags |= SOUND_FLAGS_SEQUENCE;
356 // XXX  audio_makestream(sound);
357         
358         seq = alloc_sequence(ed->seqbasep, start_frame, channel);
359         
360         seq->type= SEQ_RAM_SOUND;
361         seq->sound= sound;
362         
363         /* basic defaults */
364         seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
365         strip->len = seq->len = (int) ( ((float)(sound->streamlen-1) / ( (float)scene->r.audio.mixrate*4.0 ))* FPS);
366         strip->us= 1;
367         
368         strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
369         
370         BLI_split_dirfile_basic(filename, strip->dir, se->name);
371
372         RNA_string_get(op->ptr, "name", seq->name);
373         
374         calc_sequence_disp(seq);
375         sort_seq(scene);
376         
377         /* last active name */
378         strncpy(ed->act_sounddir, strip->dir, FILE_MAXDIR-1);
379
380         if (RNA_boolean_get(op->ptr, "replace_sel")) {
381                 deselect_all_seq(scene);
382                 set_last_seq(scene, seq);
383                 seq->flag |= SELECT;
384         }
385
386         ED_area_tag_redraw(CTX_wm_area(C));
387         
388         return OPERATOR_FINISHED;
389 }
390
391
392 static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
393 {       
394         sequencer_generic_invoke_xy__internal(C, op, event, 0);
395         return WM_operator_filesel(C, op, event);
396         //return sequencer_add_sound_strip_exec(C, op);
397 }
398
399
400 void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot)
401 {
402         
403         /* identifiers */
404         ot->name= "Add Sound Strip";
405         ot->idname= "SEQUENCER_OT_sound_strip_add";
406         ot->description= "Add a sound strip to the sequencer";
407
408         /* api callbacks */
409         ot->invoke= sequencer_add_sound_strip_invoke;
410         ot->exec= sequencer_add_sound_strip_exec;
411
412         ot->poll= ED_operator_sequencer_active;
413         
414         /* flags */
415         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
416         
417         WM_operator_properties_filesel(ot, FOLDERFILE|SOUNDFILE);
418         sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
419         RNA_def_boolean(ot->srna, "cache", FALSE, "Cache", "Load the sound as streaming audio"); // XXX need to impliment this
420 }
421
422 /* add image operator */
423 static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
424 {
425         Scene *scene= CTX_data_scene(C);
426         Editing *ed= seq_give_editing(scene, TRUE);
427
428         int tot_images;
429
430         char filename[FILE_MAX];
431
432         Sequence *seq;  /* generic strip vars */
433         Strip *strip;
434         StripElem *se;
435         
436         int start_frame, channel; /* operator props */
437         
438         start_frame= RNA_int_get(op->ptr, "start_frame");
439         channel= RNA_int_get(op->ptr, "channel");
440         
441         RNA_string_get(op->ptr, "filename", filename);
442
443         seq = alloc_sequence(ed->seqbasep, start_frame, channel);       
444         seq->type= SEQ_IMAGE;
445         
446         /* basic defaults */
447         seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
448         BLI_split_dirfile_basic(filename, strip->dir, NULL);
449         
450         tot_images= RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
451         
452         strip->len = seq->len = tot_images?tot_images:1;
453         strip->us= 1;
454         
455         strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
456         
457         if(tot_images) {
458                 RNA_BEGIN(op->ptr, itemptr, "files") {
459                         RNA_string_get(&itemptr, "name", se->name);
460                         se++;
461                 }
462                 RNA_END;
463         }
464         else {
465                 BLI_split_dirfile_basic(filename, NULL, se->name);
466         }
467
468         RNA_string_get(op->ptr, "name", seq->name);
469         
470         calc_sequence_disp(seq);
471         sort_seq(scene);
472         
473         /* last active name */
474         strncpy(ed->act_imagedir, strip->dir, FILE_MAXDIR-1);
475         
476         if (RNA_boolean_get(op->ptr, "replace_sel")) {
477                 deselect_all_seq(scene);
478                 set_last_seq(scene, seq);
479                 seq->flag |= SELECT;
480         }
481
482         ED_area_tag_redraw(CTX_wm_area(C));
483         
484         return OPERATOR_FINISHED;
485 }
486
487
488 static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
489 {
490         sequencer_generic_invoke_xy__internal(C, op, event, 0);
491         return WM_operator_filesel(C, op, event);       
492         //return sequencer_add_image_strip_exec(C, op);
493 }
494
495
496 void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
497 {
498         
499         /* identifiers */
500         ot->name= "Add Image Strip";
501         ot->idname= "SEQUENCER_OT_image_strip_add";
502         ot->description= "Add an image or image sequence to the sequencer";
503
504         /* api callbacks */
505         ot->invoke= sequencer_add_image_strip_invoke;
506         ot->exec= sequencer_add_image_strip_exec;
507
508         ot->poll= ED_operator_sequencer_active;
509         
510         /* flags */
511         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
512         
513         WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE);
514         sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
515         
516         RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", "");
517 }
518
519
520 /* add_effect_strip operator */
521 static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
522 {
523         Scene *scene= CTX_data_scene(C);
524         Editing *ed= seq_give_editing(scene, TRUE);
525
526         Sequence *seq;  /* generic strip vars */
527         Strip *strip;
528         StripElem *se;
529         struct SeqEffectHandle sh;
530
531         int start_frame, end_frame, channel, type; /* operator props */
532         
533         Sequence *seq1, *seq2, *seq3;
534         char *error_msg;
535
536         start_frame= RNA_int_get(op->ptr, "start_frame");
537         end_frame= RNA_int_get(op->ptr, "end_frame");
538         channel= RNA_int_get(op->ptr, "channel");
539
540         type= RNA_enum_get(op->ptr, "type");
541         
542         // XXX We need unique names and move to invoke
543         if(!seq_effect_find_selected(scene, NULL, type, &seq1, &seq2, &seq3, &error_msg)) {
544                 BKE_report(op->reports, RPT_ERROR, error_msg);
545                 return OPERATOR_CANCELLED;
546         }
547
548         /* If seq1 is NULL and no error was rasied it means the seq is standalone
549          * (like color strips) and we need to check its start and end frames are valid */
550         if (seq1==NULL && end_frame <= start_frame) {
551                 BKE_report(op->reports, RPT_ERROR, "Start and end frame are not set");
552                 return OPERATOR_CANCELLED;
553         }
554
555         seq = alloc_sequence(ed->seqbasep, start_frame, channel);
556         seq->type= type;
557
558         sh = get_sequence_effect(seq);
559
560         seq->seq1= seq1;
561         seq->seq2= seq2;
562         seq->seq3= seq3;
563
564         sh.init(seq);
565
566         if (!seq1) { /* effect has no deps */
567                 seq->len= 1;
568                 seq_tx_set_final_right(seq, end_frame);
569         }
570
571         calc_sequence(seq);
572         
573         /* basic defaults */
574         seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
575         strip->len = seq->len;
576         strip->us= 1;
577         if(seq->len>0)
578                 strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
579
580         if (seq->type==SEQ_PLUGIN) {
581                 char filename[FILE_MAX];
582                 RNA_string_get(op->ptr, "filename", filename);
583
584                 sh.init_plugin(seq, filename);
585
586                 if(seq->plugin==NULL) {
587                         BLI_remlink(ed->seqbasep, seq);
588                         seq_free_sequence(ed, seq);
589                         BKE_reportf(op->reports, RPT_ERROR, "Sequencer plugin \"%s\" could not load.", filename);
590                         return OPERATOR_CANCELLED;
591                 }
592         }
593         else if (seq->type==SEQ_COLOR) {
594                 SolidColorVars *colvars= (SolidColorVars *)seq->effectdata;
595                 RNA_float_get_array(op->ptr, "color", colvars->col);
596         }
597
598         if(seq_test_overlap(ed->seqbasep, seq)) shuffle_seq(ed->seqbasep, seq);
599
600         update_changed_seq_and_deps(scene, seq, 1, 1); /* runs calc_sequence */
601
602
603         /* not sure if this is needed with update_changed_seq_and_deps.
604          * it was NOT called in blender 2.4x, but wont hurt */
605         sort_seq(scene); 
606
607         if (RNA_boolean_get(op->ptr, "replace_sel")) {
608                 deselect_all_seq(scene);
609                 set_last_seq(scene, seq);
610                 seq->flag |= SELECT;
611         }
612
613         ED_area_tag_redraw(CTX_wm_area(C));
614         return OPERATOR_FINISHED;
615 }
616
617
618 /* add color */
619 static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
620 {
621         sequencer_generic_invoke_xy__internal(C, op, event, SEQPROP_ENDFRAME);
622
623         if (RNA_property_is_set(op->ptr, "type") && RNA_enum_get(op->ptr, "type")==SEQ_PLUGIN) {
624                 /* only plugins need the file selector */
625                 return WM_operator_filesel(C, op, event);
626         }
627         else {
628                 return sequencer_add_effect_strip_exec(C, op);
629         }
630 }
631
632 void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
633 {
634         /* identifiers */
635         ot->name= "Add Effect Strip";
636         ot->idname= "SEQUENCER_OT_effect_strip_add";
637         ot->description= "Add an effect to the sequencer, most are applied ontop of existing strips";
638
639         /* api callbacks */
640         ot->invoke= sequencer_add_effect_strip_invoke;
641         ot->exec= sequencer_add_effect_strip_exec;
642
643         ot->poll= ED_operator_sequencer_active;
644         
645         /* flags */
646         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
647         
648         WM_operator_properties_filesel(ot, 0);
649         sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME|SEQPROP_ENDFRAME);
650         RNA_def_enum(ot->srna, "type", sequencer_prop_effect_types, SEQ_CROSS, "Type", "Sequencer effect type");
651         RNA_def_float_vector(ot->srna, "color", 3, NULL, 0.0f, 1.0f, "Color", "Initialize the strip with this color (only used when type='COLOR')", 0.0f, 1.0f);
652 }