f6cf6de4b00eeae2edfb58b048aa62f67864c84b
[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 #define SEQPROP_FILENAME        1<<2
101
102 static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
103 {
104         RNA_def_string(ot->srna, "name", "", MAX_ID_NAME-2, "Name", "Name of the new sequence strip");
105
106         if(flag & SEQPROP_STARTFRAME)
107                 RNA_def_int(ot->srna, "start_frame", 0, INT_MIN, INT_MAX, "Start Frame", "Start frame of the sequence strip", INT_MIN, INT_MAX);
108         
109         if(flag & SEQPROP_ENDFRAME)
110                 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 */
111         
112         RNA_def_int(ot->srna, "channel", 1, 1, MAXSEQ, "Channel", "Channel to place this strip into", 1, MAXSEQ);
113         
114         if(flag & SEQPROP_FILENAME)
115                 RNA_def_string(ot->srna, "filename", "", FILE_MAX, "Scene Name", "full path to load the strip data from");
116         
117         RNA_def_boolean(ot->srna, "replace_sel", 1, "Replace Selection", "replace the current selection");
118 }
119
120 static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, wmEvent *event, int flag)
121 {
122         ARegion *ar= CTX_wm_region(C);
123         View2D *v2d= UI_view2d_fromcontext(C);
124         
125         short mval[2];  
126         float mval_v2d[2];
127         
128
129         mval[0]= event->x - ar->winrct.xmin;
130         mval[1]= event->y - ar->winrct.ymin;
131         
132         UI_view2d_region_to_view(v2d, mval[0], mval[1], &mval_v2d[0], &mval_v2d[1]);
133         
134         RNA_int_set(op->ptr, "channel", (int)mval_v2d[1]+0.5f);
135         RNA_int_set(op->ptr, "start_frame", (int)mval_v2d[0]);
136         
137         if ((flag & SEQPROP_ENDFRAME) && RNA_property_is_set(op->ptr, "end_frame")==0)
138                 RNA_int_set(op->ptr, "end_frame", (int)mval_v2d[0] + 25); // XXX arbitary but ok for now.
139         
140 }
141
142 /* add scene operator */
143 static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
144 {
145         Scene *scene= CTX_data_scene(C);
146         Editing *ed= seq_give_editing(scene, TRUE);
147         
148         Scene *sce_seq;
149         char sce_name[MAX_ID_NAME-2];
150         
151         Sequence *seq;  /* generic strip vars */
152         Strip *strip;
153         StripElem *se;
154         
155         int start_frame, channel; /* operator props */
156         
157         start_frame= RNA_int_get(op->ptr, "start_frame");
158         channel= RNA_int_get(op->ptr, "channel");
159         
160         RNA_string_get(op->ptr, "scene", sce_name);
161
162         sce_seq= (Scene *)find_id("SC", sce_name);
163         
164         if (sce_seq==NULL) {
165                 BKE_reportf(op->reports, RPT_ERROR, "Scene \"%s\" not found", sce_name);
166                 return OPERATOR_CANCELLED;
167         }
168         
169         seq = alloc_sequence(ed->seqbasep, start_frame, channel);
170         
171         seq->type= SEQ_SCENE;
172         seq->scene= sce_seq;
173         
174         /* basic defaults */
175         seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
176         strip->len = seq->len = sce_seq->r.efra - sce_seq->r.sfra + 1;
177         strip->us= 1;
178         
179         strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
180         
181         
182         RNA_string_get(op->ptr, "name", seq->name);
183         
184         calc_sequence_disp(seq);
185         sort_seq(scene);
186         
187         if (RNA_boolean_get(op->ptr, "replace_sel")) {
188                 deselect_all_seq(scene);
189                 set_last_seq(scene, seq);
190                 seq->flag |= SELECT;
191         }
192         
193         ED_area_tag_redraw(CTX_wm_area(C));
194         
195         return OPERATOR_FINISHED;
196 }
197
198
199 static int sequencer_add_scene_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
200 {
201         sequencer_generic_invoke_xy__internal(C, op, event, 0);
202         
203         /* scene can be left default */
204         RNA_string_set(op->ptr, "scene", "Scene"); // XXX should popup a menu but ton says 2.5 will have some better feature for this
205
206         return sequencer_add_scene_strip_exec(C, op);
207 }
208
209
210 void SEQUENCER_OT_scene_strip_add(struct wmOperatorType *ot)
211 {
212         
213         /* identifiers */
214         ot->name= "Add Scene Strip";
215         ot->idname= "SEQUENCER_OT_scene_strip_add";
216         ot->description= "Add a strip to the sequencer using a blender scene as a source";
217
218         /* api callbacks */
219         ot->invoke= sequencer_add_scene_strip_invoke;
220         ot->exec= sequencer_add_scene_strip_exec;
221
222         ot->poll= ED_operator_sequencer_active;
223         
224         /* flags */
225         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
226         
227         sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
228         RNA_def_string(ot->srna, "scene", "", MAX_ID_NAME-2, "Scene Name", "Scene name to add as a strip");
229 }
230
231 /* add movie operator */
232 static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
233 {
234         Scene *scene= CTX_data_scene(C);
235         Editing *ed= seq_give_editing(scene, TRUE);
236         
237         struct anim *an;
238         char filename[FILE_MAX];
239
240         Sequence *seq;  /* generic strip vars */
241         Strip *strip;
242         StripElem *se;
243         
244         int start_frame, channel; /* operator props */
245         
246         start_frame= RNA_int_get(op->ptr, "start_frame");
247         channel= RNA_int_get(op->ptr, "channel");
248         
249         RNA_string_get(op->ptr, "filename", filename);
250         
251         an = openanim(filename, IB_rect);
252
253         if (an==NULL) {
254                 BKE_reportf(op->reports, RPT_ERROR, "Filename \"%s\" could not be loaded as a movie", filename);
255                 return OPERATOR_CANCELLED;
256         }
257         
258         seq = alloc_sequence(ed->seqbasep, start_frame, channel);
259         
260         seq->type= SEQ_MOVIE;
261         seq->anim= an;
262         seq->anim_preseek = IMB_anim_get_preseek(an);
263         
264         /* basic defaults */
265         seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
266         strip->len = seq->len = IMB_anim_get_duration( an ); 
267         strip->us= 1;
268         
269         strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
270         
271         BLI_split_dirfile_basic(filename, strip->dir, se->name);
272
273         RNA_string_get(op->ptr, "name", seq->name);
274         
275         calc_sequence_disp(seq);
276         sort_seq(scene);
277
278         if (RNA_boolean_get(op->ptr, "replace_sel")) {
279                 deselect_all_seq(scene);
280                 set_last_seq(scene, seq);
281                 seq->flag |= SELECT;
282         }
283         
284         ED_area_tag_redraw(CTX_wm_area(C));
285         
286         return OPERATOR_FINISHED;
287 }
288
289
290 static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
291 {       
292         sequencer_generic_invoke_xy__internal(C, op, event, 0);
293         return WM_operator_filesel(C, op, event);
294         //return sequencer_add_movie_strip_exec(C, op);
295 }
296
297
298 void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
299 {
300         
301         /* identifiers */
302         ot->name= "Add Movie Strip";
303         ot->idname= "SEQUENCER_OT_movie_strip_add";
304         ot->description= "Add a movie strip to the sequencer";
305
306         /* api callbacks */
307         ot->invoke= sequencer_add_movie_strip_invoke;
308         ot->exec= sequencer_add_movie_strip_exec;
309
310         ot->poll= ED_operator_sequencer_active;
311         
312         /* flags */
313         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
314         
315         sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME|SEQPROP_FILENAME);
316         RNA_def_boolean(ot->srna, "sound", FALSE, "Sound", "Load hd sound with the movie"); // XXX need to impliment this
317 }
318
319
320 /* add sound operator */
321 static int sequencer_add_sound_strip_exec(bContext *C, wmOperator *op)
322 {
323         Scene *scene= CTX_data_scene(C);
324         Editing *ed= seq_give_editing(scene, TRUE);
325         
326         bSound *sound;
327
328         char filename[FILE_MAX];
329
330         Sequence *seq;  /* generic strip vars */
331         Strip *strip;
332         StripElem *se;
333         
334         int start_frame, channel; /* operator props */
335         
336         start_frame= RNA_int_get(op->ptr, "start_frame");
337         channel= RNA_int_get(op->ptr, "channel");
338         
339         RNA_string_get(op->ptr, "filename", filename);
340
341         /* XXX if(sfile->flag & FILE_STRINGCODE) {
342                 BLI_makestringcode(G.sce, str);
343         }*/
344
345 // XXX  sound= sound_new_sound(filename);
346         sound= NULL;
347
348         if (sound==NULL || sound->sample->type == SAMPLE_INVALID) {
349                 BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
350                 return OPERATOR_CANCELLED;
351         }
352
353         if (sound==NULL || sound->sample->bits != 16) {
354                 BKE_report(op->reports, RPT_ERROR, "Only 16 bit audio is supported");
355                 return OPERATOR_CANCELLED;
356         }
357         
358         sound->flags |= SOUND_FLAGS_SEQUENCE;
359 // XXX  audio_makestream(sound);
360         
361         seq = alloc_sequence(ed->seqbasep, start_frame, channel);
362         
363         seq->type= SEQ_RAM_SOUND;
364         seq->sound= sound;
365         
366         /* basic defaults */
367         seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
368         strip->len = seq->len = (int) ( ((float)(sound->streamlen-1) / ( (float)scene->r.audio.mixrate*4.0 ))* FPS);
369         strip->us= 1;
370         
371         strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
372         
373         BLI_split_dirfile_basic(filename, strip->dir, se->name);
374
375         RNA_string_get(op->ptr, "name", seq->name);
376         
377         calc_sequence_disp(seq);
378         sort_seq(scene);
379         
380         /* last active name */
381         strncpy(ed->act_sounddir, strip->dir, FILE_MAXDIR-1);
382
383         if (RNA_boolean_get(op->ptr, "replace_sel")) {
384                 deselect_all_seq(scene);
385                 set_last_seq(scene, seq);
386                 seq->flag |= SELECT;
387         }
388
389         ED_area_tag_redraw(CTX_wm_area(C));
390         
391         return OPERATOR_FINISHED;
392 }
393
394
395 static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
396 {       
397         sequencer_generic_invoke_xy__internal(C, op, event, 0);
398         return WM_operator_filesel(C, op, event);
399         //return sequencer_add_sound_strip_exec(C, op);
400 }
401
402
403 void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot)
404 {
405         
406         /* identifiers */
407         ot->name= "Add Sound Strip";
408         ot->idname= "SEQUENCER_OT_sound_strip_add";
409         ot->description= "Add a sound strip to the sequencer";
410
411         /* api callbacks */
412         ot->invoke= sequencer_add_sound_strip_invoke;
413         ot->exec= sequencer_add_sound_strip_exec;
414
415         ot->poll= ED_operator_sequencer_active;
416         
417         /* flags */
418         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
419         
420         sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME|SEQPROP_FILENAME);
421         RNA_def_boolean(ot->srna, "hd", FALSE, "HD Sound", "Load the sound as streaming audio"); // XXX need to impliment this
422 }
423
424 /* add image operator */
425 static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
426 {
427         Scene *scene= CTX_data_scene(C);
428         Editing *ed= seq_give_editing(scene, TRUE);
429
430         int tot_images;
431
432         char filename[FILE_MAX];
433
434         Sequence *seq;  /* generic strip vars */
435         Strip *strip;
436         StripElem *se;
437         
438         int start_frame, channel; /* operator props */
439         
440         start_frame= RNA_int_get(op->ptr, "start_frame");
441         channel= RNA_int_get(op->ptr, "channel");
442         
443         RNA_string_get(op->ptr, "filename", filename);
444
445         seq = alloc_sequence(ed->seqbasep, start_frame, channel);       
446         seq->type= SEQ_IMAGE;
447         
448         /* basic defaults */
449         seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
450         BLI_split_dirfile_basic(filename, strip->dir, NULL);
451         
452         tot_images= RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
453         
454         strip->len = seq->len = tot_images?tot_images:1;
455         strip->us= 1;
456         
457         strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
458         
459         if(tot_images) {
460                 RNA_BEGIN(op->ptr, itemptr, "files") {
461                         RNA_string_get(&itemptr, "name", se->name);
462                         se++;
463                 }
464                 RNA_END;
465         }
466         else {
467                 BLI_split_dirfile_basic(filename, NULL, se->name);
468         }
469
470         RNA_string_get(op->ptr, "name", seq->name);
471         
472         calc_sequence_disp(seq);
473         sort_seq(scene);
474         
475         /* last active name */
476         strncpy(ed->act_imagedir, strip->dir, FILE_MAXDIR-1);
477         
478         if (RNA_boolean_get(op->ptr, "replace_sel")) {
479                 deselect_all_seq(scene);
480                 set_last_seq(scene, seq);
481                 seq->flag |= SELECT;
482         }
483
484         ED_area_tag_redraw(CTX_wm_area(C));
485         
486         return OPERATOR_FINISHED;
487 }
488
489
490 static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
491 {
492         sequencer_generic_invoke_xy__internal(C, op, event, 0);
493         return WM_operator_filesel(C, op, event);       
494         //return sequencer_add_image_strip_exec(C, op);
495 }
496
497
498 void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
499 {
500         
501         /* identifiers */
502         ot->name= "Add Image Strip";
503         ot->idname= "SEQUENCER_OT_image_strip_add";
504         ot->description= "Add an image or image sequence to the sequencer";
505
506         /* api callbacks */
507         ot->invoke= sequencer_add_image_strip_invoke;
508         ot->exec= sequencer_add_image_strip_exec;
509
510         ot->poll= ED_operator_sequencer_active;
511         
512         /* flags */
513         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
514         
515         sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME|SEQPROP_FILENAME);
516         
517         RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", "");
518 }
519
520
521 /* add_effect_strip operator */
522 static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
523 {
524         Scene *scene= CTX_data_scene(C);
525         Editing *ed= seq_give_editing(scene, TRUE);
526
527         Sequence *seq;  /* generic strip vars */
528         Strip *strip;
529         StripElem *se;
530         struct SeqEffectHandle sh;
531
532         int start_frame, end_frame, channel, type; /* operator props */
533         
534         Sequence *seq1, *seq2, *seq3;
535         char *error_msg;
536
537         start_frame= RNA_int_get(op->ptr, "start_frame");
538         end_frame= RNA_int_get(op->ptr, "end_frame");
539         channel= RNA_int_get(op->ptr, "channel");
540
541         type= RNA_enum_get(op->ptr, "type");
542         
543         // XXX We need unique names and move to invoke
544         if(!seq_effect_find_selected(scene, NULL, type, &seq1, &seq2, &seq3, &error_msg)) {
545                 BKE_report(op->reports, RPT_ERROR, error_msg);
546                 return OPERATOR_CANCELLED;
547         }
548
549         /* If seq1 is NULL and no error was rasied it means the seq is standalone
550          * (like color strips) and we need to check its start and end frames are valid */
551         if (seq1==NULL && end_frame <= start_frame) {
552                 BKE_report(op->reports, RPT_ERROR, "Start and end frame are not set");
553                 return OPERATOR_CANCELLED;
554         }
555
556         seq = alloc_sequence(ed->seqbasep, start_frame, channel);
557         seq->type= type;
558
559         sh = get_sequence_effect(seq);
560
561         seq->seq1= seq1;
562         seq->seq2= seq2;
563         seq->seq3= seq3;
564
565         sh.init(seq);
566
567         if (!seq1) { /* effect has no deps */
568                 seq->len= 1;
569                 seq_tx_set_final_right(seq, end_frame);
570         }
571
572         calc_sequence(seq);
573         
574         /* basic defaults */
575         seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
576         strip->len = seq->len;
577         strip->us= 1;
578         if(seq->len>0)
579                 strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
580
581         if (seq->type==SEQ_PLUGIN) {
582                 char filename[FILE_MAX];
583                 RNA_string_get(op->ptr, "filename", filename);
584
585                 sh.init_plugin(seq, filename);
586
587                 if(seq->plugin==NULL) {
588                         BLI_remlink(ed->seqbasep, seq);
589                         seq_free_sequence(ed, seq);
590                         BKE_reportf(op->reports, RPT_ERROR, "Sequencer plugin \"%s\" could not load.", filename);
591                         return OPERATOR_CANCELLED;
592                 }
593         }
594         else if (seq->type==SEQ_COLOR) {
595                 SolidColorVars *colvars= (SolidColorVars *)seq->effectdata;
596                 RNA_float_get_array(op->ptr, "color", colvars->col);
597         }
598
599         if(seq_test_overlap(ed->seqbasep, seq)) shuffle_seq(ed->seqbasep, seq);
600
601         update_changed_seq_and_deps(scene, seq, 1, 1); /* runs calc_sequence */
602
603
604         /* not sure if this is needed with update_changed_seq_and_deps.
605          * it was NOT called in blender 2.4x, but wont hurt */
606         sort_seq(scene); 
607
608         if (RNA_boolean_get(op->ptr, "replace_sel")) {
609                 deselect_all_seq(scene);
610                 set_last_seq(scene, seq);
611                 seq->flag |= SELECT;
612         }
613
614         ED_area_tag_redraw(CTX_wm_area(C));
615         return OPERATOR_FINISHED;
616 }
617
618
619 /* add color */
620 static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, wmEvent *event)
621 {
622         sequencer_generic_invoke_xy__internal(C, op, event, SEQPROP_ENDFRAME);
623
624         if (RNA_property_is_set(op->ptr, "type") && RNA_enum_get(op->ptr, "type")==SEQ_PLUGIN) {
625                 /* only plugins need the file selector */
626                 return WM_operator_filesel(C, op, event);
627         }
628         else {
629                 return sequencer_add_effect_strip_exec(C, op);
630         }
631 }
632
633 void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
634 {
635         /* identifiers */
636         ot->name= "Add Effect Strip";
637         ot->idname= "SEQUENCER_OT_effect_strip_add";
638         ot->description= "Add an effect to the sequencer, most are applied ontop of existing strips";
639
640         /* api callbacks */
641         ot->invoke= sequencer_add_effect_strip_invoke;
642         ot->exec= sequencer_add_effect_strip_exec;
643
644         ot->poll= ED_operator_sequencer_active;
645         
646         /* flags */
647         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
648         
649         sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME|SEQPROP_ENDFRAME|SEQPROP_FILENAME);
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 }