diff options
Diffstat (limited to 'source/blender/editors/space_sequencer')
-rw-r--r-- | source/blender/editors/space_sequencer/Makefile | 56 | ||||
-rw-r--r-- | source/blender/editors/space_sequencer/SConscript | 10 | ||||
-rw-r--r-- | source/blender/editors/space_sequencer/sequencer_add.c | 652 | ||||
-rw-r--r-- | source/blender/editors/space_sequencer/sequencer_buttons.c | 136 | ||||
-rw-r--r-- | source/blender/editors/space_sequencer/sequencer_draw.c | 1093 | ||||
-rw-r--r-- | source/blender/editors/space_sequencer/sequencer_edit.c | 2409 | ||||
-rw-r--r-- | source/blender/editors/space_sequencer/sequencer_intern.h | 154 | ||||
-rw-r--r-- | source/blender/editors/space_sequencer/sequencer_ops.c | 185 | ||||
-rw-r--r-- | source/blender/editors/space_sequencer/sequencer_scopes.c | 701 | ||||
-rw-r--r-- | source/blender/editors/space_sequencer/sequencer_select.c | 819 | ||||
-rw-r--r-- | source/blender/editors/space_sequencer/space_sequencer.c | 301 |
11 files changed, 6516 insertions, 0 deletions
diff --git a/source/blender/editors/space_sequencer/Makefile b/source/blender/editors/space_sequencer/Makefile new file mode 100644 index 00000000000..80699db4baa --- /dev/null +++ b/source/blender/editors/space_sequencer/Makefile @@ -0,0 +1,56 @@ +# +# $Id: Makefile 14 2002-10-13 15:57:19Z hans $ +# +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# The Original Code is Copyright (C) 2007 Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): none yet. +# +# ***** END GPL LICENSE BLOCK ***** +# +# Makes module object directory and bounces make to subdirectories. + +LIBNAME = ed_sequencer +DIR = $(OCGDIR)/blender/$(LIBNAME) + +include nan_compile.mk + +CFLAGS += $(LEVEL_1_C_WARNINGS) + +CPPFLAGS += -I$(NAN_GLEW)/include +CPPFLAGS += -I$(OPENGL_HEADERS) + + +# not very neat.... +CPPFLAGS += -I../../windowmanager +CPPFLAGS += -I../../blenloader +CPPFLAGS += -I../../blenkernel +CPPFLAGS += -I../../blenlib +CPPFLAGS += -I../../makesdna +CPPFLAGS += -I../../makesrna +CPPFLAGS += -I../../imbuf +CPPFLAGS += -I../../python +CPPFLAGS += -I../../blenfont +CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include + +# own include + +CPPFLAGS += -I../include diff --git a/source/blender/editors/space_sequencer/SConscript b/source/blender/editors/space_sequencer/SConscript new file mode 100644 index 00000000000..ab51068a529 --- /dev/null +++ b/source/blender/editors/space_sequencer/SConscript @@ -0,0 +1,10 @@ +#!/usr/bin/python +Import ('env') + +sources = env.Glob('*.c') + +incs = '../include ../../blenlib ../../blenkernel ../../blenfont ../../makesdna ../../imbuf' +incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' +incs += ' ../../makesrna' + +env.BlenderLib ( 'bf_editors_space_sequencer', sources, Split(incs), [], libtype=['core'], priority=[100] ) diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c new file mode 100644 index 00000000000..f6cf6de4b00 --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -0,0 +1,652 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation, 2003-2009, Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <math.h> +#include <string.h> + +#ifndef WIN32 +#include <unistd.h> +#else +#include <io.h> +#endif +#include <sys/types.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_storage_types.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "DNA_ipo_types.h" +#include "DNA_curve_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_sequence_types.h" +#include "DNA_view2d_types.h" +#include "DNA_userdef_types.h" +#include "DNA_sound_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_plugin_types.h" +#include "BKE_sequence.h" +#include "BKE_scene.h" +#include "BKE_utildefines.h" +#include "BKE_report.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +/* for menu/popup icons etc etc*/ +#include "UI_interface.h" +#include "UI_resources.h" + +#include "ED_anim_api.h" +#include "ED_space_api.h" +#include "ED_types.h" +#include "ED_screen.h" +#include "ED_util.h" +#include "ED_fileselect.h" + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +/* own include */ +#include "sequencer_intern.h" + +/* Generic functions, reused by add strip operators */ + +/* avoid passing multiple args and be more verbose */ +#define SEQPROP_STARTFRAME 1<<0 +#define SEQPROP_ENDFRAME 1<<1 +#define SEQPROP_FILENAME 1<<2 + +static void sequencer_generic_props__internal(wmOperatorType *ot, int flag) +{ + RNA_def_string(ot->srna, "name", "", MAX_ID_NAME-2, "Name", "Name of the new sequence strip"); + + if(flag & SEQPROP_STARTFRAME) + RNA_def_int(ot->srna, "start_frame", 0, INT_MIN, INT_MAX, "Start Frame", "Start frame of the sequence strip", INT_MIN, INT_MAX); + + if(flag & SEQPROP_ENDFRAME) + 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 */ + + RNA_def_int(ot->srna, "channel", 1, 1, MAXSEQ, "Channel", "Channel to place this strip into", 1, MAXSEQ); + + if(flag & SEQPROP_FILENAME) + RNA_def_string(ot->srna, "filename", "", FILE_MAX, "Scene Name", "full path to load the strip data from"); + + RNA_def_boolean(ot->srna, "replace_sel", 1, "Replace Selection", "replace the current selection"); +} + +static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, wmEvent *event, int flag) +{ + ARegion *ar= CTX_wm_region(C); + View2D *v2d= UI_view2d_fromcontext(C); + + short mval[2]; + float mval_v2d[2]; + + + mval[0]= event->x - ar->winrct.xmin; + mval[1]= event->y - ar->winrct.ymin; + + UI_view2d_region_to_view(v2d, mval[0], mval[1], &mval_v2d[0], &mval_v2d[1]); + + RNA_int_set(op->ptr, "channel", (int)mval_v2d[1]+0.5f); + RNA_int_set(op->ptr, "start_frame", (int)mval_v2d[0]); + + if ((flag & SEQPROP_ENDFRAME) && RNA_property_is_set(op->ptr, "end_frame")==0) + RNA_int_set(op->ptr, "end_frame", (int)mval_v2d[0] + 25); // XXX arbitary but ok for now. + +} + +/* add scene operator */ +static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, TRUE); + + Scene *sce_seq; + char sce_name[MAX_ID_NAME-2]; + + Sequence *seq; /* generic strip vars */ + Strip *strip; + StripElem *se; + + int start_frame, channel; /* operator props */ + + start_frame= RNA_int_get(op->ptr, "start_frame"); + channel= RNA_int_get(op->ptr, "channel"); + + RNA_string_get(op->ptr, "scene", sce_name); + + sce_seq= (Scene *)find_id("SC", sce_name); + + if (sce_seq==NULL) { + BKE_reportf(op->reports, RPT_ERROR, "Scene \"%s\" not found", sce_name); + return OPERATOR_CANCELLED; + } + + seq = alloc_sequence(ed->seqbasep, start_frame, channel); + + seq->type= SEQ_SCENE; + seq->scene= sce_seq; + + /* basic defaults */ + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strip->len = seq->len = sce_seq->r.efra - sce_seq->r.sfra + 1; + strip->us= 1; + + strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); + + + RNA_string_get(op->ptr, "name", seq->name); + + calc_sequence_disp(seq); + sort_seq(scene); + + if (RNA_boolean_get(op->ptr, "replace_sel")) { + deselect_all_seq(scene); + set_last_seq(scene, seq); + seq->flag |= SELECT; + } + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + + +static int sequencer_add_scene_strip_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + sequencer_generic_invoke_xy__internal(C, op, event, 0); + + /* scene can be left default */ + RNA_string_set(op->ptr, "scene", "Scene"); // XXX should popup a menu but ton says 2.5 will have some better feature for this + + return sequencer_add_scene_strip_exec(C, op); +} + + +void SEQUENCER_OT_scene_strip_add(struct wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Add Scene Strip"; + ot->idname= "SEQUENCER_OT_scene_strip_add"; + ot->description= "Add a strip to the sequencer using a blender scene as a source"; + + /* api callbacks */ + ot->invoke= sequencer_add_scene_strip_invoke; + ot->exec= sequencer_add_scene_strip_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME); + RNA_def_string(ot->srna, "scene", "", MAX_ID_NAME-2, "Scene Name", "Scene name to add as a strip"); +} + +/* add movie operator */ +static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, TRUE); + + struct anim *an; + char filename[FILE_MAX]; + + Sequence *seq; /* generic strip vars */ + Strip *strip; + StripElem *se; + + int start_frame, channel; /* operator props */ + + start_frame= RNA_int_get(op->ptr, "start_frame"); + channel= RNA_int_get(op->ptr, "channel"); + + RNA_string_get(op->ptr, "filename", filename); + + an = openanim(filename, IB_rect); + + if (an==NULL) { + BKE_reportf(op->reports, RPT_ERROR, "Filename \"%s\" could not be loaded as a movie", filename); + return OPERATOR_CANCELLED; + } + + seq = alloc_sequence(ed->seqbasep, start_frame, channel); + + seq->type= SEQ_MOVIE; + seq->anim= an; + seq->anim_preseek = IMB_anim_get_preseek(an); + + /* basic defaults */ + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strip->len = seq->len = IMB_anim_get_duration( an ); + strip->us= 1; + + strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); + + BLI_split_dirfile_basic(filename, strip->dir, se->name); + + RNA_string_get(op->ptr, "name", seq->name); + + calc_sequence_disp(seq); + sort_seq(scene); + + if (RNA_boolean_get(op->ptr, "replace_sel")) { + deselect_all_seq(scene); + set_last_seq(scene, seq); + seq->flag |= SELECT; + } + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + + +static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + sequencer_generic_invoke_xy__internal(C, op, event, 0); + return WM_operator_filesel(C, op, event); + //return sequencer_add_movie_strip_exec(C, op); +} + + +void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Add Movie Strip"; + ot->idname= "SEQUENCER_OT_movie_strip_add"; + ot->description= "Add a movie strip to the sequencer"; + + /* api callbacks */ + ot->invoke= sequencer_add_movie_strip_invoke; + ot->exec= sequencer_add_movie_strip_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME|SEQPROP_FILENAME); + RNA_def_boolean(ot->srna, "sound", FALSE, "Sound", "Load hd sound with the movie"); // XXX need to impliment this +} + + +/* add sound operator */ +static int sequencer_add_sound_strip_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, TRUE); + + bSound *sound; + + char filename[FILE_MAX]; + + Sequence *seq; /* generic strip vars */ + Strip *strip; + StripElem *se; + + int start_frame, channel; /* operator props */ + + start_frame= RNA_int_get(op->ptr, "start_frame"); + channel= RNA_int_get(op->ptr, "channel"); + + RNA_string_get(op->ptr, "filename", filename); + + /* XXX if(sfile->flag & FILE_STRINGCODE) { + BLI_makestringcode(G.sce, str); + }*/ + +// XXX sound= sound_new_sound(filename); + sound= NULL; + + if (sound==NULL || sound->sample->type == SAMPLE_INVALID) { + BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); + return OPERATOR_CANCELLED; + } + + if (sound==NULL || sound->sample->bits != 16) { + BKE_report(op->reports, RPT_ERROR, "Only 16 bit audio is supported"); + return OPERATOR_CANCELLED; + } + + sound->flags |= SOUND_FLAGS_SEQUENCE; +// XXX audio_makestream(sound); + + seq = alloc_sequence(ed->seqbasep, start_frame, channel); + + seq->type= SEQ_RAM_SOUND; + seq->sound= sound; + + /* basic defaults */ + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strip->len = seq->len = (int) ( ((float)(sound->streamlen-1) / ( (float)scene->r.audio.mixrate*4.0 ))* FPS); + strip->us= 1; + + strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); + + BLI_split_dirfile_basic(filename, strip->dir, se->name); + + RNA_string_get(op->ptr, "name", seq->name); + + calc_sequence_disp(seq); + sort_seq(scene); + + /* last active name */ + strncpy(ed->act_sounddir, strip->dir, FILE_MAXDIR-1); + + if (RNA_boolean_get(op->ptr, "replace_sel")) { + deselect_all_seq(scene); + set_last_seq(scene, seq); + seq->flag |= SELECT; + } + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + + +static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + sequencer_generic_invoke_xy__internal(C, op, event, 0); + return WM_operator_filesel(C, op, event); + //return sequencer_add_sound_strip_exec(C, op); +} + + +void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Add Sound Strip"; + ot->idname= "SEQUENCER_OT_sound_strip_add"; + ot->description= "Add a sound strip to the sequencer"; + + /* api callbacks */ + ot->invoke= sequencer_add_sound_strip_invoke; + ot->exec= sequencer_add_sound_strip_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME|SEQPROP_FILENAME); + RNA_def_boolean(ot->srna, "hd", FALSE, "HD Sound", "Load the sound as streaming audio"); // XXX need to impliment this +} + +/* add image operator */ +static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, TRUE); + + int tot_images; + + char filename[FILE_MAX]; + + Sequence *seq; /* generic strip vars */ + Strip *strip; + StripElem *se; + + int start_frame, channel; /* operator props */ + + start_frame= RNA_int_get(op->ptr, "start_frame"); + channel= RNA_int_get(op->ptr, "channel"); + + RNA_string_get(op->ptr, "filename", filename); + + seq = alloc_sequence(ed->seqbasep, start_frame, channel); + seq->type= SEQ_IMAGE; + + /* basic defaults */ + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + BLI_split_dirfile_basic(filename, strip->dir, NULL); + + tot_images= RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files")); + + strip->len = seq->len = tot_images?tot_images:1; + strip->us= 1; + + strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); + + if(tot_images) { + RNA_BEGIN(op->ptr, itemptr, "files") { + RNA_string_get(&itemptr, "name", se->name); + se++; + } + RNA_END; + } + else { + BLI_split_dirfile_basic(filename, NULL, se->name); + } + + RNA_string_get(op->ptr, "name", seq->name); + + calc_sequence_disp(seq); + sort_seq(scene); + + /* last active name */ + strncpy(ed->act_imagedir, strip->dir, FILE_MAXDIR-1); + + if (RNA_boolean_get(op->ptr, "replace_sel")) { + deselect_all_seq(scene); + set_last_seq(scene, seq); + seq->flag |= SELECT; + } + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + + +static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + sequencer_generic_invoke_xy__internal(C, op, event, 0); + return WM_operator_filesel(C, op, event); + //return sequencer_add_image_strip_exec(C, op); +} + + +void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Add Image Strip"; + ot->idname= "SEQUENCER_OT_image_strip_add"; + ot->description= "Add an image or image sequence to the sequencer"; + + /* api callbacks */ + ot->invoke= sequencer_add_image_strip_invoke; + ot->exec= sequencer_add_image_strip_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME|SEQPROP_FILENAME); + + RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", ""); +} + + +/* add_effect_strip operator */ +static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, TRUE); + + Sequence *seq; /* generic strip vars */ + Strip *strip; + StripElem *se; + struct SeqEffectHandle sh; + + int start_frame, end_frame, channel, type; /* operator props */ + + Sequence *seq1, *seq2, *seq3; + char *error_msg; + + start_frame= RNA_int_get(op->ptr, "start_frame"); + end_frame= RNA_int_get(op->ptr, "end_frame"); + channel= RNA_int_get(op->ptr, "channel"); + + type= RNA_enum_get(op->ptr, "type"); + + // XXX We need unique names and move to invoke + if(!seq_effect_find_selected(scene, NULL, type, &seq1, &seq2, &seq3, &error_msg)) { + BKE_report(op->reports, RPT_ERROR, error_msg); + return OPERATOR_CANCELLED; + } + + /* If seq1 is NULL and no error was rasied it means the seq is standalone + * (like color strips) and we need to check its start and end frames are valid */ + if (seq1==NULL && end_frame <= start_frame) { + BKE_report(op->reports, RPT_ERROR, "Start and end frame are not set"); + return OPERATOR_CANCELLED; + } + + seq = alloc_sequence(ed->seqbasep, start_frame, channel); + seq->type= type; + + sh = get_sequence_effect(seq); + + seq->seq1= seq1; + seq->seq2= seq2; + seq->seq3= seq3; + + sh.init(seq); + + if (!seq1) { /* effect has no deps */ + seq->len= 1; + seq_tx_set_final_right(seq, end_frame); + } + + calc_sequence(seq); + + /* basic defaults */ + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strip->len = seq->len; + strip->us= 1; + if(seq->len>0) + strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem"); + + if (seq->type==SEQ_PLUGIN) { + char filename[FILE_MAX]; + RNA_string_get(op->ptr, "filename", filename); + + sh.init_plugin(seq, filename); + + if(seq->plugin==NULL) { + BLI_remlink(ed->seqbasep, seq); + seq_free_sequence(ed, seq); + BKE_reportf(op->reports, RPT_ERROR, "Sequencer plugin \"%s\" could not load.", filename); + return OPERATOR_CANCELLED; + } + } + else if (seq->type==SEQ_COLOR) { + SolidColorVars *colvars= (SolidColorVars *)seq->effectdata; + RNA_float_get_array(op->ptr, "color", colvars->col); + } + + if(seq_test_overlap(ed->seqbasep, seq)) shuffle_seq(ed->seqbasep, seq); + + update_changed_seq_and_deps(scene, seq, 1, 1); /* runs calc_sequence */ + + + /* not sure if this is needed with update_changed_seq_and_deps. + * it was NOT called in blender 2.4x, but wont hurt */ + sort_seq(scene); + + if (RNA_boolean_get(op->ptr, "replace_sel")) { + deselect_all_seq(scene); + set_last_seq(scene, seq); + seq->flag |= SELECT; + } + + ED_area_tag_redraw(CTX_wm_area(C)); + return OPERATOR_FINISHED; +} + + +/* add color */ +static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + sequencer_generic_invoke_xy__internal(C, op, event, SEQPROP_ENDFRAME); + + if (RNA_property_is_set(op->ptr, "type") && RNA_enum_get(op->ptr, "type")==SEQ_PLUGIN) { + /* only plugins need the file selector */ + return WM_operator_filesel(C, op, event); + } + else { + return sequencer_add_effect_strip_exec(C, op); + } +} + +void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Add Effect Strip"; + ot->idname= "SEQUENCER_OT_effect_strip_add"; + ot->description= "Add an effect to the sequencer, most are applied ontop of existing strips"; + + /* api callbacks */ + ot->invoke= sequencer_add_effect_strip_invoke; + ot->exec= sequencer_add_effect_strip_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME|SEQPROP_ENDFRAME|SEQPROP_FILENAME); + RNA_def_enum(ot->srna, "type", sequencer_prop_effect_types, SEQ_CROSS, "Type", "Sequencer effect type"); + 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); +} diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c new file mode 100644 index 00000000000..f127ab4b0cf --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_buttons.c @@ -0,0 +1,136 @@ +/** + * $Id: sequencer_buttons.c 20279 2009-05-19 17:13:33Z blendix $ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 by Blender Foundation + * All rights reserved. + * + * ***** END GPL LICENSE BLOCK ***** + */ + + +#include <string.h> +#include <stdio.h> + +#include "DNA_object_types.h" +#include "DNA_space_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_userdef_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_screen.h" +#include "BKE_utildefines.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "ED_screen.h" +#include "ED_sequencer.h" +#include "ED_util.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "sequencer_intern.h" + + +static void do_sequencer_panel_events(bContext *C, void *arg, int event) +{ + +} + + +static void sequencer_panel_view_properties(const bContext *C, Panel *pa) +{ + uiBlock *block; + + block= uiLayoutFreeBlock(pa->layout); + uiBlockSetHandleFunc(block, do_sequencer_panel_events, NULL); + +} + + +static void sequencer_panel_properties(const bContext *C, Panel *pa) +{ + uiBlock *block; + + block= uiLayoutFreeBlock(pa->layout); + uiBlockSetHandleFunc(block, do_sequencer_panel_events, NULL); + +} + +void sequencer_buttons_register(ARegionType *art) +{ + PanelType *pt; + + pt= MEM_callocN(sizeof(PanelType), "spacetype sequencer strip properties"); + strcpy(pt->idname, "SEQUENCER_PT_properties"); + strcpy(pt->label, "Strip Properties"); + pt->draw= sequencer_panel_properties; + BLI_addtail(&art->paneltypes, pt); + + pt= MEM_callocN(sizeof(PanelType), "spacetype sequencer view properties"); + strcpy(pt->idname, "SEQUENCER_PT_view_properties"); + strcpy(pt->label, "View Properties"); + pt->draw= sequencer_panel_view_properties; + BLI_addtail(&art->paneltypes, pt); + +} + +/* **************** operator to open/close properties view ************* */ + +static int sequencer_properties(bContext *C, wmOperator *op) +{ + ScrArea *sa= CTX_wm_area(C); + ARegion *ar= sequencer_has_buttons_region(sa); + + if(ar) { + ar->flag ^= RGN_FLAG_HIDDEN; + ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */ + + ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa); + ED_area_tag_redraw(sa); + } + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_properties(wmOperatorType *ot) +{ + ot->name= "Properties"; + ot->idname= "SEQUENCER_OT_properties"; + + ot->exec= sequencer_properties; + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= 0; +} + diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c new file mode 100644 index 00000000000..bd31d8d86ff --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -0,0 +1,1093 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation, 2003-2009 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "IMB_imbuf_types.h" + +#include "DNA_gpencil_types.h" +#include "DNA_sequence_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view2d_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_plugin_types.h" +#include "BKE_sequence.h" +#include "BKE_scene.h" +#include "BKE_utildefines.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "ED_anim_api.h" +#include "ED_space_api.h" +#include "ED_sequencer.h" +#include "ED_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +/* own include */ +#include "sequencer_intern.h" + +#define SEQ_LEFTHANDLE 1 +#define SEQ_RIGHTHANDLE 2 + + +/* Note, Dont use WHILE_SEQ while drawing! - it messes up transform, - Campbell */ + +int no_rightbox=0, no_leftbox= 0; +static void draw_shadedstrip(Sequence *seq, char *col, float x1, float y1, float x2, float y2); + + +static void draw_cfra_seq(View2D *v2d, int cfra) +{ + glColor3ub(0x30, 0x90, 0x50); + glLineWidth(2.0); + glBegin(GL_LINES); + glVertex2f(cfra, v2d->cur.ymin); + glVertex2f(cfra, v2d->cur.ymax); + glEnd(); + glLineWidth(1.0); +} + +static void get_seq_color3ubv(Scene *curscene, Sequence *seq, char *col) +{ + char blendcol[3]; + float hsv[3], rgb[3]; + SolidColorVars *colvars = (SolidColorVars *)seq->effectdata; + + switch(seq->type) { + case SEQ_IMAGE: + UI_GetThemeColor3ubv(TH_SEQ_IMAGE, col); + break; + case SEQ_META: + UI_GetThemeColor3ubv(TH_SEQ_META, col); + break; + case SEQ_MOVIE: + UI_GetThemeColor3ubv(TH_SEQ_MOVIE, col); + break; + case SEQ_SCENE: + UI_GetThemeColor3ubv(TH_SEQ_SCENE, col); + + if(seq->scene==curscene) { + UI_GetColorPtrBlendShade3ubv(col, col, col, 1.0, 20); + } + break; + + /* transitions */ + case SEQ_CROSS: + case SEQ_GAMCROSS: + case SEQ_WIPE: + /* slightly offset hue to distinguish different effects */ + UI_GetThemeColor3ubv(TH_SEQ_TRANSITION, col); + + rgb[0] = col[0]/255.0; rgb[1] = col[1]/255.0; rgb[2] = col[2]/255.0; + rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2); + + if (seq->type == SEQ_CROSS) hsv[0]+= 0.04; + if (seq->type == SEQ_GAMCROSS) hsv[0]+= 0.08; + if (seq->type == SEQ_WIPE) hsv[0]+= 0.12; + + if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0; + hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2); + col[0] = (char)(rgb[0]*255); col[1] = (char)(rgb[1]*255); col[2] = (char)(rgb[2]*255); + break; + + /* effects */ + case SEQ_TRANSFORM: + case SEQ_SPEED: + case SEQ_ADD: + case SEQ_SUB: + case SEQ_MUL: + case SEQ_ALPHAOVER: + case SEQ_ALPHAUNDER: + case SEQ_OVERDROP: + case SEQ_GLOW: + /* slightly offset hue to distinguish different effects */ + UI_GetThemeColor3ubv(TH_SEQ_EFFECT, col); + + rgb[0] = col[0]/255.0; rgb[1] = col[1]/255.0; rgb[2] = col[2]/255.0; + rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2); + + if (seq->type == SEQ_ADD) hsv[0]+= 0.04; + if (seq->type == SEQ_SUB) hsv[0]+= 0.08; + if (seq->type == SEQ_MUL) hsv[0]+= 0.12; + if (seq->type == SEQ_ALPHAOVER) hsv[0]+= 0.16; + if (seq->type == SEQ_ALPHAUNDER) hsv[0]+= 0.20; + if (seq->type == SEQ_OVERDROP) hsv[0]+= 0.24; + if (seq->type == SEQ_GLOW) hsv[0]+= 0.28; + if (seq->type == SEQ_TRANSFORM) hsv[0]+= 0.36; + + if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0; + hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2); + col[0] = (char)(rgb[0]*255); col[1] = (char)(rgb[1]*255); col[2] = (char)(rgb[2]*255); + break; + case SEQ_COLOR: + if (colvars->col) { + col[0]= (char)(colvars->col[0]*255); + col[1]= (char)(colvars->col[1]*255); + col[2]= (char)(colvars->col[2]*255); + } else { + col[0] = col[1] = col[2] = 128; + } + break; + case SEQ_PLUGIN: + UI_GetThemeColor3ubv(TH_SEQ_PLUGIN, col); + break; + case SEQ_HD_SOUND: + case SEQ_RAM_SOUND: + UI_GetThemeColor3ubv(TH_SEQ_AUDIO, col); + blendcol[0] = blendcol[1] = blendcol[2] = 128; + if(seq->flag & SEQ_MUTE) UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.5, 20); + break; + default: + col[0] = 10; col[1] = 255; col[2] = 40; + } +} + +static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, float x2, float y2) +{ + /* Note, this used to use WHILE_SEQ, but it messes up the seq->depth value, (needed by transform when doing overlap checks) + * so for now, just use the meta's immediate children, could be fixed but its only drawing - Campbell */ + Sequence *seq; + float dx; + int nr; + char col[3]; + + nr= BLI_countlist(&seqm->seqbase); + + dx= (x2-x1)/nr; + + if (seqm->flag & SEQ_MUTE) { + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple(stipple_halftone); + + glEnable(GL_LINE_STIPPLE); + glLineStipple(1, 0x8888); + } + + for (seq= seqm->seqbase.first; seq; seq= seq->next) { + get_seq_color3ubv(scene, seq, col); + + glColor3ubv((GLubyte *)col); + + glRectf(x1, y1, x1+0.9*dx, y2); + + UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -30); + glColor3ubv((GLubyte *)col); + + fdrawbox(x1, y1, x1+0.9*dx, y2); + + x1+= dx; + } + + if (seqm->flag & SEQ_MUTE) { + glDisable(GL_POLYGON_STIPPLE); + glDisable(GL_LINE_STIPPLE); + } +} + +static void drawseqwave(Scene *scene, View2D *v2d, Sequence *seq, float x1, float y1, float x2, float y2, int winx) +{ + /* + x1 is the starting x value to draw the wave, + x2 the end x value, same for y1 and y2 + winx is the zoom level. + */ + + float + f, /* floating point value used to store the X draw location for the wave lines when openGL drawing*/ + midy, /* fast access to the middle location (y1+y2)/2 */ + clipxmin, /* the minimum X value, clip this with the window */ + clipxmax, /* the maximum X value, clip this with the window */ + sample_step, /* steps to move per sample, floating value must later translate into an int */ + fsofs, /* steps to move per sample, floating value must later translate into an int */ + feofs_sofs, /* */ + sound_width, /* convenience: x2-x1 */ + wavemulti; /* scale the samples by this value when GL_LINE drawing so it renders the right height */ + + int + offset, /* initial offset value for the wave drawing */ + offset_next, /* when in the wave drawing loop this value is the samples intil the next vert */ + sofs, /* Constrained offset value (~3) for the wave, start */ + eofs, /* ditto, end */ + wavesample, /* inner loop storage if the current wave sample value, used to make the 2 values below */ + wavesamplemin, /* used for finding the min and max wave peaks */ + wavesamplemax, /* ditto */ + subsample_step=4; /* when the sample step is 4 every sample of + the wave is evaluated for min and max values used to draw the wave, + however this is slow ehrn zoomed out so when the sample step is above + 1 (the larger the further out the zoom is) so not evaluate all samples, only some. */ + + signed short* s; + bSound *sound; + uint8_t *stream; + +// XXX audio_makestream(seq->sound); + if(seq->sound==NULL || seq->sound->stream==NULL) return; + + if (seq->flag & SEQ_MUTE) glColor3ub(0x70, 0x80, 0x80); else glColor3ub(0x70, 0xc0, 0xc0); + + sofs = ((int)( FRA2TIME(seq->startdisp-seq->start+seq->anim_startofs)*(float)scene->r.audio.mixrate*4.0 )) & (~3); + eofs = ((int)( FRA2TIME(seq->enddisp-seq->start+seq->anim_startofs)*(float)scene->r.audio.mixrate*4.0 )) & (~3); + + /* clip the drawing area to the screen bounds to save time */ + sample_step= (v2d->cur.xmax - v2d->cur.xmin)/winx; + clipxmin= MAX2(x1, v2d->cur.xmin); + clipxmax= MIN2(x2, v2d->cur.xmax); + + if (sample_step > 1) + subsample_step= ((int)(subsample_step*sample_step*8)) & (~3); + + /* for speedy access */ + midy = (y1+y2)/2; + fsofs= (float)sofs; + feofs_sofs= (float)(eofs-sofs); + sound_width= x2-x1; + sound = seq->sound; + stream = sound->stream; + wavemulti = (y2-y1)/196605; /*y2-y1 is the height*/ + wavesample=0; + + /* we need to get the starting offset value, excuse the duplicate code */ + f=clipxmin; + offset= (int) (fsofs + ((f-x1)/sound_width) * feofs_sofs) & (~3); + + /* start the loop, draw a line per sample_step -sample_step is about 1 line drawn per pixel */ + glBegin(GL_LINES); + for (f=x1+sample_step; f<=clipxmax; f+=sample_step) { + + offset_next = (int) (fsofs + ((f-x1)/sound_width) * feofs_sofs) & (~3); + if (f > v2d->cur.xmin) { + /* if this is close to the last sample just exit */ + if (offset_next >= sound->streamlen) break; + + wavesamplemin = 131070; + wavesamplemax = -131070; + + /*find with high and low of the waveform for this draw, + evaluate small samples to find this range */ + while (offset < offset_next) { + s = (signed short*)(stream+offset); + + wavesample = s[0]*2 + s[1]; + if (wavesamplemin>wavesample) + wavesamplemin=wavesample; + if (wavesamplemax<wavesample) + wavesamplemax=wavesample; + offset+=subsample_step; + } + /* draw the wave line, looks good up close and zoomed out */ + glVertex2f(f, midy-(wavemulti*wavesamplemin) ); + glVertex2f(f, midy-(wavemulti*wavesamplemax) ); + } else { + while (offset < offset_next) offset+=subsample_step; + } + + offset=offset_next; + } + glEnd(); +} + +/* draw a handle, for each end of a sequence strip */ +static void draw_seq_handle(View2D *v2d, Sequence *seq, float pixelx, short direction) +{ + float v1[2], v2[2], v3[2], rx1=0, rx2=0; //for triangles and rect + float x1, x2, y1, y2; + float handsize; + float minhandle, maxhandle; + char str[32]; + unsigned int whichsel=0; + + x1= seq->startdisp; + x2= seq->enddisp; + + y1= seq->machine+SEQ_STRIP_OFSBOTTOM; + y2= seq->machine+SEQ_STRIP_OFSTOP; + + /* clamp handles to defined size in pixel space */ + handsize = seq->handsize; + minhandle = 7; + maxhandle = 40; + CLAMP(handsize, minhandle*pixelx, maxhandle*pixelx); + + /* set up co-ordinates/dimensions for either left or right handle */ + if (direction == SEQ_LEFTHANDLE) { + rx1 = x1; + rx2 = x1+handsize*0.75; + + v1[0]= x1+handsize/4; v1[1]= y1+( ((y1+y2)/2.0 - y1)/2); + v2[0]= x1+handsize/4; v2[1]= y2-( ((y1+y2)/2.0 - y1)/2); + v3[0]= v2[0] + handsize/4; v3[1]= (y1+y2)/2.0; + + whichsel = SEQ_LEFTSEL; + } else if (direction == SEQ_RIGHTHANDLE) { + rx1 = x2-handsize*0.75; + rx2 = x2; + + v1[0]= x2-handsize/4; v1[1]= y1+( ((y1+y2)/2.0 - y1)/2); + v2[0]= x2-handsize/4; v2[1]= y2-( ((y1+y2)/2.0 - y1)/2); + v3[0]= v2[0] - handsize/4; v3[1]= (y1+y2)/2.0; + + whichsel = SEQ_RIGHTSEL; + } + + /* draw! */ + if(seq->type < SEQ_EFFECT || + get_sequence_effect_num_inputs(seq->type) == 0) { + glEnable( GL_BLEND ); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + if(seq->flag & whichsel) glColor4ub(0, 0, 0, 80); + else if (seq->flag & SELECT) glColor4ub(255, 255, 255, 30); + else glColor4ub(0, 0, 0, 22); + + glRectf(rx1, y1, rx2, y2); + + if(seq->flag & whichsel) glColor4ub(255, 255, 255, 200); + else glColor4ub(0, 0, 0, 50); + + glEnable( GL_POLYGON_SMOOTH ); + glBegin(GL_TRIANGLES); + glVertex2fv(v1); glVertex2fv(v2); glVertex2fv(v3); + glEnd(); + + glDisable( GL_POLYGON_SMOOTH ); + glDisable( GL_BLEND ); + } + + if(G.moving || (seq->flag & whichsel)) { + cpack(0xFFFFFF); + if (direction == SEQ_LEFTHANDLE) { + sprintf(str, "%d", seq->startdisp); + x1= rx1; + y1 -= 0.45; + } else { + sprintf(str, "%d", seq->enddisp - 1); + x1= x2 - handsize*0.75; + y1= y2 + 0.05; + } + UI_view2d_text_cache_add(v2d, x1, y1, str); + } +} + +static void draw_seq_extensions(Scene *scene, SpaceSeq *sseq, Sequence *seq) +{ + float x1, x2, y1, y2, pixely, a; + char col[3], blendcol[3]; + View2D *v2d; + + if(seq->type >= SEQ_EFFECT) return; + + x1= seq->startdisp; + x2= seq->enddisp; + + y1= seq->machine+SEQ_STRIP_OFSBOTTOM; + y2= seq->machine+SEQ_STRIP_OFSTOP; + + v2d = &sseq->v2d; + pixely = (v2d->cur.ymax - v2d->cur.ymin)/(v2d->mask.ymax - v2d->mask.ymin); + + blendcol[0] = blendcol[1] = blendcol[2] = 120; + + if(seq->startofs) { + glEnable( GL_BLEND ); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + get_seq_color3ubv(scene, seq, col); + + if (seq->flag & SELECT) { + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40); + glColor4ub(col[0], col[1], col[2], 170); + } else { + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0); + glColor4ub(col[0], col[1], col[2], 110); + } + + glRectf((float)(seq->start), y1-SEQ_STRIP_OFSBOTTOM, x1, y1); + + if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255); + else glColor4ub(col[0], col[1], col[2], 160); + + fdrawbox((float)(seq->start), y1-SEQ_STRIP_OFSBOTTOM, x1, y1); //outline + + glDisable( GL_BLEND ); + } + if(seq->endofs) { + glEnable( GL_BLEND ); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + get_seq_color3ubv(scene, seq, col); + + if (seq->flag & SELECT) { + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40); + glColor4ub(col[0], col[1], col[2], 170); + } else { + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0); + glColor4ub(col[0], col[1], col[2], 110); + } + + glRectf(x2, y2, (float)(seq->start+seq->len), y2+SEQ_STRIP_OFSBOTTOM); + + if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255); + else glColor4ub(col[0], col[1], col[2], 160); + + fdrawbox(x2, y2, (float)(seq->start+seq->len), y2+SEQ_STRIP_OFSBOTTOM); //outline + + glDisable( GL_BLEND ); + } + if(seq->startstill) { + get_seq_color3ubv(scene, seq, col); + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40); + glColor3ubv((GLubyte *)col); + + draw_shadedstrip(seq, col, x1, y1, (float)(seq->start), y2); + + /* feint pinstripes, helps see exactly which is extended and which isn't, + * especially when the extension is very small */ + if (seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 24); + else UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -16); + + glColor3ubv((GLubyte *)col); + + for(a=y1; a< y2; a+= pixely*2.0 ) { + fdrawline(x1, a, (float)(seq->start), a); + } + } + if(seq->endstill) { + get_seq_color3ubv(scene, seq, col); + UI_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40); + glColor3ubv((GLubyte *)col); + + draw_shadedstrip(seq, col, (float)(seq->start+seq->len), y1, x2, y2); + + /* feint pinstripes, helps see exactly which is extended and which isn't, + * especially when the extension is very small */ + if (seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 24); + else UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -16); + + glColor3ubv((GLubyte *)col); + + for(a=y1; a< y2; a+= pixely*2.0 ) { + fdrawline((float)(seq->start+seq->len), a, x2, a); + } + } +} + +/* draw info text on a sequence strip */ +static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float y1, float y2, char *background_col) +{ + rctf rect; + char str[32 + FILE_MAXDIR+FILE_MAXFILE]; + + if(seq->name[2]) { + sprintf(str, "%d | %s: %s", seq->len, give_seqname(seq), seq->name+2); + } + else{ + if(seq->type == SEQ_META) { + sprintf(str, "%d | %s", seq->len, give_seqname(seq)); + } + else if(seq->type == SEQ_SCENE) { + if(seq->scene) sprintf(str, "%d | %s: %s", seq->len, give_seqname(seq), seq->scene->id.name+2); + else sprintf(str, "%d | %s", seq->len, give_seqname(seq)); + + } + else if(seq->type == SEQ_IMAGE) { + sprintf(str, "%d | %s%s", seq->len, seq->strip->dir, seq->strip->stripdata->name); + } + else if(seq->type & SEQ_EFFECT) { + int can_float = (seq->type != SEQ_PLUGIN) + || (seq->plugin && seq->plugin->version >= 4); + + if(seq->seq3!=seq->seq2 && seq->seq1!=seq->seq3) + sprintf(str, "%d | %s: %d>%d (use %d)%s", seq->len, give_seqname(seq), seq->seq1->machine, seq->seq2->machine, seq->seq3->machine, can_float ? "" : " No float, upgrade plugin!"); + else if (seq->seq1 && seq->seq2) + sprintf(str, "%d | %s: %d>%d%s", seq->len, give_seqname(seq), seq->seq1->machine, seq->seq2->machine, can_float ? "" : " No float, upgrade plugin!"); + else + sprintf(str, "%d | %s", seq->len, give_seqname(seq)); + } + else if (seq->type == SEQ_RAM_SOUND) { + sprintf(str, "%d | %s", seq->len, seq->strip->stripdata->name); + } + else if (seq->type == SEQ_HD_SOUND) { + sprintf(str, "%d | %s", seq->len, seq->strip->stripdata->name); + } + else if (seq->type == SEQ_MOVIE) { + sprintf(str, "%d | %s%s", seq->len, seq->strip->dir, seq->strip->stripdata->name); + } + } + + if(seq->flag & SELECT){ + cpack(0xFFFFFF); + }else if ((((int)background_col[0] + (int)background_col[1] + (int)background_col[2]) / 3) < 50){ + cpack(0x505050); /* use lighter text colour for dark background */ + }else{ + cpack(0); + } + + rect.xmin= x1; + rect.ymin= y1; + rect.xmax= x2; + rect.ymax= y2; + UI_view2d_text_cache_rectf(v2d, &rect, str); +} + +/* draws a shaded strip, made from gradient + flat color + gradient */ +static void draw_shadedstrip(Sequence *seq, char *col, float x1, float y1, float x2, float y2) +{ + float ymid1, ymid2; + + if (seq->flag & SEQ_MUTE) { + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple(stipple_halftone); + } + + ymid1 = (y2-y1)*0.25 + y1; + ymid2 = (y2-y1)*0.65 + y1; + + glShadeModel(GL_SMOOTH); + glBegin(GL_QUADS); + + if(seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -50); + else UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 0); + + glColor3ubv((GLubyte *)col); + + glVertex2f(x1,y1); + glVertex2f(x2,y1); + + if(seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 5); + else UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -5); + + glColor3ubv((GLubyte *)col); + + glVertex2f(x2,ymid1); + glVertex2f(x1,ymid1); + + glEnd(); + + glRectf(x1, ymid1, x2, ymid2); + + glBegin(GL_QUADS); + + glVertex2f(x1,ymid2); + glVertex2f(x2,ymid2); + + if(seq->flag & SELECT) UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -15); + else UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 25); + + glColor3ubv((GLubyte *)col); + + glVertex2f(x2,y2); + glVertex2f(x1,y2); + + glEnd(); + + if (seq->flag & SEQ_MUTE) { + glDisable(GL_POLYGON_STIPPLE); + } +} + +/* +Draw a sequence strip, bounds check alredy made +ARegion is currently only used to get the windows width in pixels +so wave file sample drawing precission is zoom adjusted +*/ +static void draw_seq_strip(Scene *scene, ARegion *ar, SpaceSeq *sseq, Sequence *seq, int outline_tint, float pixelx) +{ + // XXX + extern void gl_round_box_shade(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown); + View2D *v2d= &ar->v2d; + float x1, x2, y1, y2; + char col[3], background_col[3], is_single_image; + + /* we need to know if this is a single image/color or not for drawing */ + is_single_image = (char)check_single_seq(seq); + + /* body */ + if(seq->startstill) x1= seq->start; + else x1= seq->startdisp; + y1= seq->machine+SEQ_STRIP_OFSBOTTOM; + if(seq->endstill) x2= seq->start+seq->len; + else x2= seq->enddisp; + y2= seq->machine+SEQ_STRIP_OFSTOP; + + + /* get the correct color per strip type*/ + //get_seq_color3ubv(scene, seq, col); + get_seq_color3ubv(scene, seq, background_col); + + /* draw the main strip body */ + if (is_single_image) /* single image */ + draw_shadedstrip(seq, background_col, seq_tx_get_final_left(seq, 0), y1, seq_tx_get_final_right(seq, 0), y2); + else /* normal operation */ + draw_shadedstrip(seq, background_col, x1, y1, x2, y2); + + /* draw additional info and controls */ + if (seq->type == SEQ_RAM_SOUND) + drawseqwave(scene, v2d, seq, x1, y1, x2, y2, ar->winx); + + if (!is_single_image) + draw_seq_extensions(scene, sseq, seq); + + draw_seq_handle(v2d, seq, pixelx, SEQ_LEFTHANDLE); + draw_seq_handle(v2d, seq, pixelx, SEQ_RIGHTHANDLE); + + /* draw the strip outline */ + x1= seq->startdisp; + x2= seq->enddisp; + + get_seq_color3ubv(scene, seq, col); + if (G.moving && (seq->flag & SELECT)) { + if(seq->flag & SEQ_OVERLAP) { + col[0]= 255; col[1]= col[2]= 40; + } else UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 120); + } + + UI_GetColorPtrBlendShade3ubv(col, col, col, 0.0, outline_tint); + + glColor3ubv((GLubyte *)col); + + if (seq->flag & SEQ_MUTE) { + glEnable(GL_LINE_STIPPLE); + glLineStipple(1, 0x8888); + } + + gl_round_box_shade(GL_LINE_LOOP, x1, y1, x2, y2, 0.0, 0.1, 0.0); + + if (seq->flag & SEQ_MUTE) { + glDisable(GL_LINE_STIPPLE); + } + + /* calculate if seq is long enough to print a name */ + x1= seq->startdisp+seq->handsize; + x2= seq->enddisp-seq->handsize; + + /* but first the contents of a meta */ + if(seq->type==SEQ_META) drawmeta_contents(scene, seq, x1, y1+0.15, x2, y2-0.15); + + /* info text on the strip */ + if(x1<v2d->cur.xmin) x1= v2d->cur.xmin; + else if(x1>v2d->cur.xmax) x1= v2d->cur.xmax; + if(x2<v2d->cur.xmin) x2= v2d->cur.xmin; + else if(x2>v2d->cur.xmax) x2= v2d->cur.xmax; + + /* nice text here would require changing the view matrix for texture text */ + if( (x2-x1) / pixelx > 32) { + draw_seq_text(v2d, seq, x1, x2, y1, y2, background_col); + } +} + +static Sequence *special_seq_update= 0; + +void set_special_seq_update(int val) +{ +// int x; + + /* if mouse over a sequence && LEFTMOUSE */ + if(val) { +// XXX special_seq_update= find_nearest_seq(&x); + } + else special_seq_update= 0; +} + + +static void draw_image_seq(Scene *scene, ARegion *ar, SpaceSeq *sseq) +{ + extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad); + struct ImBuf *ibuf; + int x1, y1, rectx, recty; + int free_ibuf = 0; + static int recursive= 0; + float zoom; + float zoomx, zoomy; + int render_size = 0; + + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + + render_size = sseq->render_size; + if (render_size == 0) { + render_size = scene->r.size; + } + if (render_size < 0) { + return; + } + + rectx= (render_size*scene->r.xsch)/100; + recty= (render_size*scene->r.ysch)/100; + + /* BIG PROBLEM: the give_ibuf_seq() can call a rendering, which in turn calls redraws... + this shouldn't belong in a window drawing.... + So: solve this once event based. + Now we check for recursion, space type and active area again (ton) */ + + if(recursive) + return; + else { + recursive= 1; + if (special_seq_update) { + ibuf= give_ibuf_seq_direct(scene, rectx, recty, (scene->r.cfra), render_size, special_seq_update); + } + else if (!U.prefetchframes) { // XXX || (G.f & G_PLAYANIM) == 0) { + ibuf= (ImBuf *)give_ibuf_seq(scene, rectx, recty, (scene->r.cfra), sseq->chanshown, render_size); + } + else { + ibuf= (ImBuf *)give_ibuf_seq_threaded(scene, rectx, recty, (scene->r.cfra), sseq->chanshown, render_size); + } + recursive= 0; + + /* XXX HURMF! the give_ibuf_seq can call image display in this window */ +// if(sa->spacetype!=SPACE_SEQ) +// return; +// if(sa!=curarea) { +// areawinset(sa->win); +// } + } + + if(ibuf==NULL) + return; + + if(ibuf->rect==NULL && ibuf->rect_float == NULL) + return; + + switch(sseq->mainb != SEQ_DRAW_SEQUENCE) { + case SEQ_DRAW_IMG_IMBUF: + if (sseq->zebra != 0) { + ibuf = make_zebra_view_from_ibuf(ibuf, sseq->zebra); + free_ibuf = 1; + } + break; + case SEQ_DRAW_IMG_WAVEFORM: + if ((sseq->flag & SEQ_DRAW_COLOR_SEPERATED) != 0) { + ibuf = make_sep_waveform_view_from_ibuf(ibuf); + } else { + ibuf = make_waveform_view_from_ibuf(ibuf); + } + free_ibuf = 1; + break; + case SEQ_DRAW_IMG_VECTORSCOPE: + ibuf = make_vectorscope_view_from_ibuf(ibuf); + free_ibuf = 1; + break; + case SEQ_DRAW_IMG_HISTOGRAM: + ibuf = make_histogram_view_from_ibuf(ibuf); + free_ibuf = 1; + break; + } + + if(ibuf->rect_float && ibuf->rect==NULL) + IMB_rect_from_float(ibuf); + + /* needed for gla draw */ + glaDefine2DArea(&ar->winrct); + + zoom= SEQ_ZOOM_FAC(sseq->zoom); + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) { + zoom /= render_size / 100.0; + zoomx = zoom * ((float)scene->r.xasp / (float)scene->r.yasp); + zoomy = zoom; + } else { + zoomx = zoomy = zoom; + } + + /* calc location */ + x1= (ar->winx-zoomx*ibuf->x)/2 + sseq->xof; + y1= (ar->winy-zoomy*ibuf->y)/2 + sseq->yof; + + glPixelZoom(zoomx, zoomy); + + glaDrawPixelsSafe(x1, y1, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); + + glPixelZoom(1.0, 1.0); + + /* safety border */ + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && + (sseq->flag & SEQ_DRAW_SAFE_MARGINS) != 0) { + float fac= 0.1; + float x2 = x1 + ibuf->x * zoomx; + float y2 = y1 + ibuf->y * zoomy; + + float a= fac*(x2-x1); + x1+= a; + x2-= a; + + a= fac*(y2-y1); + y1+= a; + y2-= a; + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + setlinestyle(3); + + UI_ThemeColorBlendShade(TH_WIRE, TH_BACK, 1.0, 0); + + uiSetRoundBox(15); + gl_round_box(GL_LINE_LOOP, x1, y1, x2, y2, 12.0); + + setlinestyle(0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + + /* draw grease-pencil (image aligned) */ +// if (sseq->flag & SEQ_DRAW_GPENCIL) +// XXX draw_gpencil_2dimage(sa, ibuf); + + if (free_ibuf) { + IMB_freeImBuf(ibuf); + } + + /* draw grease-pencil (screen aligned) */ +// if (sseq->flag & SEQ_DRAW_GPENCIL) +// XXX draw_gpencil_2dview(sa, 0); + + /* ortho at pixel level sa */ +// XXX myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375); + +} + +void seq_reset_imageofs(SpaceSeq *sseq) +{ + sseq->xof = sseq->yof = sseq->zoom = 0; +} + + +#if 0 +/* XXX - these should really be made to use View2D instead of so wacko private system - Aligorith */ + +void seq_viewzoom(SpaceSeq *sseq, unsigned short event, int invert) +{ + + if(event==PAD1) + sseq->zoom= 1.0; + else if(event==PAD2) + sseq->zoom= (invert)? 2.0: 0.5; + else if(event==PAD4) + sseq->zoom= (invert)? 4.0: 0.25; + else if(event==PAD8) + sseq->zoom= (invert)? 8.0: 0.125; + + /* ensure pixel exact locations for draw */ + sseq->xof= (int)sseq->xof; + sseq->yof= (int)sseq->yof; +} + +void seq_viewmove(Scene *scene, ARegion *ar, SpaceSeq *sseq) +{ + short mval[2], mvalo[2]; + short rectx, recty, xmin, xmax, ymin, ymax, pad; + int oldcursor; + Window *win; + + sa = sseq->area; + rectx= (scene->r.size*scene->r.xsch)/100; + recty= (scene->r.size*scene->r.ysch)/100; + + pad = 10; + xmin = -(ar->winx/2) - rectx/2 + pad; + xmax = ar->winx/2 + rectx/2 - pad; + ymin = -(ar->winy/2) - recty/2 + pad; + ymax = ar->winy/2 + recty/2 - pad; + + getmouseco_sc(mvalo); + + oldcursor=get_cursor(); + win=winlay_get_active_window(); + + SetBlenderCursor(BC_NSEW_SCROLLCURSOR); + + while(get_mbut()&(L_MOUSE|M_MOUSE)) { + + getmouseco_sc(mval); + + if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) { + + sseq->xof -= (mvalo[0]-mval[0]); + sseq->yof -= (mvalo[1]-mval[1]); + + /* prevent dragging image outside of the window and losing it! */ + CLAMP(sseq->xof, xmin, xmax); + CLAMP(sseq->yof, ymin, ymax); + + mvalo[0]= mval[0]; + mvalo[1]= mval[1]; + + } + } +} +#endif + +void drawprefetchseqspace(Scene *scene, ARegion *ar, SpaceSeq *sseq) +{ + int rectx, recty; + int render_size = sseq->render_size; + if (render_size == 0) { + render_size = scene->r.size; + } + if (render_size < 0) { + return; + } + + rectx= (render_size*scene->r.xsch)/100; + recty= (render_size*scene->r.ysch)/100; + + if(sseq->mainb != SEQ_DRAW_SEQUENCE) { + give_ibuf_prefetch_request( + rectx, recty, (scene->r.cfra), sseq->chanshown, + render_size); + } +} + +void drawseqspace(const bContext *C, ARegion *ar) +{ + ScrArea *sa= CTX_wm_area(C); + SpaceSeq *sseq= sa->spacedata.first; + Scene *scene= CTX_data_scene(C); + View2D *v2d= &ar->v2d; + View2DScrollers *scrollers; + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq; + float col[3]; + int i; + + if(sseq->mainb != SEQ_DRAW_SEQUENCE) { + draw_image_seq(scene, ar, sseq); + return; + } + + UI_GetThemeColor3fv(TH_BACK, col); + if(ed && ed->metastack.first) glClearColor(col[0], col[1], col[2]-0.1, 0.0); + else glClearColor(col[0], col[1], col[2], 0.0); + + glClear(GL_COLOR_BUFFER_BIT); + + UI_view2d_view_ortho(C, v2d); + + UI_ThemeColorShade(TH_BACK, -20); + glRectf(v2d->cur.xmin, 0.0, v2d->cur.xmax, 1.0); + + boundbox_seq(scene, &v2d->tot); + + /* Alternating horizontal stripes */ + i= MAX2(1, ((int)v2d->cur.ymin)-1); + + glBegin(GL_QUADS); + while (i<v2d->cur.ymax) { + if (((int)i) & 1) + UI_ThemeColorShade(TH_BACK, -15); + else + UI_ThemeColorShade(TH_BACK, -25); + + glVertex2f(v2d->cur.xmax, i); + glVertex2f(v2d->cur.xmin, i); + glVertex2f(v2d->cur.xmin, i+1); + glVertex2f(v2d->cur.xmax, i+1); + i+=1.0; + } + glEnd(); + + /* Force grid lines */ + i= MAX2(1, ((int)v2d->cur.ymin)-1); + glBegin(GL_LINES); + + while (i<v2d->cur.ymax) { + UI_ThemeColor(TH_GRID); + glVertex2f(v2d->cur.xmax, i); + glVertex2f(v2d->cur.xmin, i); + i+=1.0; + } + glEnd(); + + UI_view2d_constant_grid_draw(C, v2d); + + draw_cfra_seq(v2d, scene->r.cfra); + + /* sequences: first deselect */ + if(ed) { + Sequence *last_seq = get_last_seq(scene); + int sel = 0, j; + int outline_tint; + float pixelx = (v2d->cur.xmax - v2d->cur.xmin)/(v2d->mask.xmax - v2d->mask.xmin); + /* loop through twice, first unselected, then selected */ + for (j=0; j<2; j++) { + seq= ed->seqbasep->first; + if (j==0) outline_tint = -150; + else outline_tint = -60; + + while(seq) { /* bound box test, dont draw outside the view */ + if ( ((seq->flag & SELECT) == sel) || + seq == last_seq || + MIN2(seq->startdisp, seq->start) > v2d->cur.xmax || + MAX2(seq->enddisp, seq->start+seq->len) < v2d->cur.xmin || + seq->machine+1.0 < v2d->cur.ymin || + seq->machine > v2d->cur.ymax) + { + /* dont draw */ + } else { + draw_seq_strip(scene, ar, sseq, seq, outline_tint, pixelx); + } + seq= seq->next; + } + sel= SELECT; /* draw selected next time round */ + } + /* draw the last selected last, removes some overlapping error */ + if (last_seq) { + draw_seq_strip(scene, ar, sseq, last_seq, 120, pixelx); + } + } + + /* text draw cached, in pixelspace now */ + UI_view2d_text_cache_draw(ar); + + /* Draw markers */ +// draw_markers_timespace(SCE_MARKERS, DRAW_MARKERS_LINES); + + /* reset view matrix */ + UI_view2d_view_restore(C); + + /* scrollers */ + scrollers= UI_view2d_scrollers_calc(C, v2d, V2D_UNIT_SECONDSSEQ, V2D_GRID_CLAMP, V2D_UNIT_VALUES, V2D_GRID_CLAMP); + UI_view2d_scrollers_draw(C, v2d, scrollers); + UI_view2d_scrollers_free(scrollers); +} + + diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c new file mode 100644 index 00000000000..9c3191c93d6 --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -0,0 +1,2409 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation, 2003-2009 + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <math.h> +#include <string.h> + +#ifndef WIN32 +#include <unistd.h> +#else +#include <io.h> +#endif +#include <sys/types.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_storage_types.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "DNA_ipo_types.h" +#include "DNA_curve_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_sequence_types.h" +#include "DNA_view2d_types.h" +#include "DNA_userdef_types.h" +#include "DNA_sound_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_plugin_types.h" +#include "BKE_sequence.h" +#include "BKE_scene.h" +#include "BKE_utildefines.h" +#include "BKE_report.h" + +#include "BIF_transform.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +/* for menu/popup icons etc etc*/ +#include "UI_interface.h" +#include "UI_resources.h" + +#include "ED_anim_api.h" +#include "ED_space_api.h" +#include "ED_types.h" +#include "ED_screen.h" +#include "ED_util.h" + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +/* own include */ +#include "sequencer_intern.h" + +/* XXX */ +//static Sequence *_last_seq=0; +//static int _last_seq_init=0; +/* XXX */ +static void error() {} +static void waitcursor() {} +static void activate_fileselect() {} +static int pupmenu() {return 0;} +static int okee() {return 0;} + + +/* XXX */ +/* RNA Enums, used in multiple files */ +EnumPropertyItem sequencer_prop_effect_types[] = { + {SEQ_CROSS, "CROSS", "Crossfade", "Crossfade effect strip type"}, + {SEQ_ADD, "ADD", "Add", "Add effect strip type"}, + {SEQ_SUB, "SUBTRACT", "Subtract", "Subtract effect strip type"}, + {SEQ_ALPHAOVER, "ALPHA_OVER", "Alpha Over", "Alpha Over effect strip type"}, + {SEQ_ALPHAUNDER, "ALPHA_UNDER", "Alpha Under", "Alpha Under effect strip type"}, + {SEQ_GAMCROSS, "GAMMA_CROSS", "Gamma Cross", "Gamma Cross effect strip type"}, + {SEQ_MUL, "MULTIPLY", "Multiply", "Multiply effect strip type"}, + {SEQ_OVERDROP, "OVER_DROP", "Alpha Over Drop", "Alpha Over Drop effect strip type"}, + {SEQ_PLUGIN, "PLUGIN", "Plugin", "Plugin effect strip type"}, + {SEQ_WIPE, "WIPE", "Wipe", "Wipe effect strip type"}, + {SEQ_GLOW, "GLOW", "Glow", "Glow effect strip type"}, + {SEQ_TRANSFORM, "TRANSFORM", "Transform", "Transform effect strip type"}, + {SEQ_COLOR, "COLOR", "Color", "Color effect strip type"}, + {SEQ_SPEED, "SPEED", "Speed", "Color effect strip type"}, + {0, NULL, NULL, NULL} +}; + +/* mute operator */ +EnumPropertyItem sequencer_prop_operate_types[] = { /* better name? */ + {SEQ_SELECTED, "SELECTED", "Selected", ""}, + {SEQ_UNSELECTED, "UNSELECTED", "Unselected ", ""}, + {0, NULL, NULL, NULL} +}; + + EnumPropertyItem prop_side_types[] = { + {SEQ_SIDE_LEFT, "LEFT", "Left", ""}, + {SEQ_SIDE_RIGHT, "RIGHT", "Right", ""}, + {SEQ_SIDE_BOTH, "BOTH", "Both", ""}, + {0, NULL, NULL, NULL} +}; + +typedef struct TransSeq { + int start, machine; + int startstill, endstill; + int startdisp, enddisp; + int startofs, endofs; + int final_left, final_right; + int len; +} TransSeq; + +Sequence *get_last_seq(Scene *scene) +{ + Editing *ed= seq_give_editing(scene, FALSE); + if(ed==NULL) return NULL; + return ed->act_seq; +} + +void set_last_seq(Scene *scene, Sequence *seq) +{ + Editing *ed= seq_give_editing(scene, FALSE); + if(ed==NULL) return; + + ed->act_seq= seq; +} + +Sequence *get_foreground_frame_seq(Scene *scene, int frame) +{ + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq, *best_seq=NULL; + int best_machine = -1; + + if(!ed) return NULL; + + for (seq=ed->seqbasep->first; seq; seq= seq->next) { + if(seq->flag & SEQ_MUTE || seq->startdisp > frame || seq->enddisp <= frame) + continue; + /* only use elements you can see - not */ + if (ELEM6(seq->type, SEQ_IMAGE, SEQ_META, SEQ_SCENE, SEQ_MOVIE, SEQ_MOVIE_AND_HD_SOUND, SEQ_COLOR)) { + if (seq->machine > best_machine) { + best_seq = seq; + best_machine = seq->machine; + } + } + } + return best_seq; +} + +void seq_rectf(Sequence *seq, rctf *rectf) +{ + if(seq->startstill) rectf->xmin= seq->start; + else rectf->xmin= seq->startdisp; + rectf->ymin= seq->machine+SEQ_STRIP_OFSBOTTOM; + if(seq->endstill) rectf->xmax= seq->start+seq->len; + else rectf->xmax= seq->enddisp; + rectf->ymax= seq->machine+SEQ_STRIP_OFSTOP; +} + +static void change_plugin_seq(Scene *scene, char *str) /* called from fileselect */ +{ + Editing *ed= seq_give_editing(scene, FALSE); + struct SeqEffectHandle sh; + Sequence *last_seq= get_last_seq(scene); + + if(last_seq && last_seq->type != SEQ_PLUGIN) return; + + sh = get_sequence_effect(last_seq); + sh.free(last_seq); + sh.init_plugin(last_seq, str); + + last_seq->machine = MAX3(last_seq->seq1->machine, + last_seq->seq2->machine, + last_seq->seq3->machine); + + if( seq_test_overlap(ed->seqbasep, last_seq) ) shuffle_seq(ed->seqbasep, last_seq); + +} + + +void boundbox_seq(Scene *scene, rctf *rect) +{ + Sequence *seq; + Editing *ed= seq_give_editing(scene, FALSE); + float min[2], max[2]; + + + if(ed==NULL) return; + + min[0]= 0.0; + max[0]= EFRA+1; + min[1]= 0.0; + max[1]= 8.0; + + seq= ed->seqbasep->first; + while(seq) { + + if( min[0] > seq->startdisp-1) min[0]= seq->startdisp-1; + if( max[0] < seq->enddisp+1) max[0]= seq->enddisp+1; + if( max[1] < seq->machine+2.0) max[1]= seq->machine+2.0; + + seq= seq->next; + } + + rect->xmin= min[0]; + rect->xmax= max[0]; + rect->ymin= min[1]; + rect->ymax= max[1]; + +} + +int mouse_frame_side(View2D *v2d, short mouse_x, int frame ) +{ + short mval[2]; + float mouseloc[2]; + + mval[0]= mouse_x; + mval[1]= 0; + + /* choose the side based on which side of the playhead the mouse is on */ + UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouseloc[0], &mouseloc[1]); + + return mouseloc[0] > frame ? SEQ_SIDE_RIGHT : SEQ_SIDE_LEFT; +} + + +Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int sel) +{ + /* sel - 0==unselected, 1==selected, -1==done care*/ + Sequence *seq; + Editing *ed= seq_give_editing(scene, FALSE); + + if(ed==NULL) return NULL; + + if (sel>0) sel = SELECT; + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + if( (seq!=test) && + (test->machine==seq->machine) && + ((sel == -1) || (sel && (seq->flag & SELECT)) || (sel==0 && (seq->flag & SELECT)==0) )) + { + switch (lr) { + case SEQ_SIDE_LEFT: + if (test->startdisp == (seq->enddisp)) { + return seq; + } + break; + case SEQ_SIDE_RIGHT: + if (test->enddisp == (seq->startdisp)) { + return seq; + } + break; + } + } + } + return NULL; +} + +Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, int sel) +{ + /* sel - 0==unselected, 1==selected, -1==done care*/ + Sequence *seq,*best_seq = NULL; + Editing *ed= seq_give_editing(scene, FALSE); + + int dist, best_dist; + best_dist = MAXFRAME*2; + + + if(ed==NULL) return NULL; + + if (sel) sel = SELECT; + + seq= ed->seqbasep->first; + while(seq) { + if( (seq!=test) && + (test->machine==seq->machine) && + (test->depth==seq->depth) && + ((sel == -1) || (sel==(seq->flag & SELECT)))) + { + dist = MAXFRAME*2; + + switch (lr) { + case SEQ_SIDE_LEFT: + if (seq->enddisp <= test->startdisp) { + dist = test->enddisp - seq->startdisp; + } + break; + case SEQ_SIDE_RIGHT: + if (seq->startdisp >= test->enddisp) { + dist = seq->startdisp - test->enddisp; + } + break; + } + + if (dist==0) { + best_seq = seq; + break; + } else if (dist < best_dist) { + best_dist = dist; + best_seq = seq; + } + } + seq= seq->next; + } + return best_seq; /* can be null */ +} + + +Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, short mval[2]) +{ + Sequence *seq; + Editing *ed= seq_give_editing(scene, FALSE); + float x, y; + float pixelx; + float handsize; + float displen; + *hand= SEQ_SIDE_NONE; + + + if(ed==NULL) return NULL; + + pixelx = (v2d->cur.xmax - v2d->cur.xmin)/(v2d->mask.xmax - v2d->mask.xmin); + + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + + seq= ed->seqbasep->first; + + while(seq) { + if(seq->machine == (int)y) { + /* check for both normal strips, and strips that have been flipped horizontally */ + if( ((seq->startdisp < seq->enddisp) && (seq->startdisp<=x && seq->enddisp>=x)) || + ((seq->startdisp > seq->enddisp) && (seq->startdisp>=x && seq->enddisp<=x)) ) + { + if(seq_tx_test(seq)) { + + /* clamp handles to defined size in pixel space */ + + handsize = seq->handsize; + displen = (float)abs(seq->startdisp - seq->enddisp); + + if (displen / pixelx > 16) { /* dont even try to grab the handles of small strips */ + /* Set the max value to handle to 1/3 of the total len when its less then 28. + * This is important because otherwise selecting handles happens even when you click in the middle */ + + if ((displen/3) < 30*pixelx) { + handsize = displen/3; + } else { + CLAMP(handsize, 7*pixelx, 30*pixelx); + } + + if( handsize+seq->startdisp >=x ) + *hand= SEQ_SIDE_LEFT; + else if( -handsize+seq->enddisp <=x ) + *hand= SEQ_SIDE_RIGHT; + } + } + return seq; + } + } + seq= seq->next; + } + return 0; +} + +void update_seq_ipo_rect(Scene *scene, View2D *v2d, Sequence *seq) +{ + float start; + float end; + + if (!seq || !seq->ipo) { + return; + } + start = -5.0; + end = 105.0; + + + /* Adjust IPO window to sequence and + avoid annoying snap-back to startframe + when Lock Time is on */ + if (0) { // XXX v2d->flag & V2D_VIEWLOCK) { + if ((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) { + start = -5.0 + seq->startdisp; + end = 5.0 + seq->enddisp; + } else { + start = (float)scene->r.sfra - 0.1; + end = scene->r.efra; + } + } + + seq->ipo->cur.xmin= start; + seq->ipo->cur.xmax= end; +} + +void update_seq_icu_rects(Sequence * seq) +{ + IpoCurve *icu= NULL; + struct SeqEffectHandle sh; + + if (!seq || !seq->ipo) { + return; + } + + if(!(seq->type & SEQ_EFFECT)) { + return; + } + + sh = get_sequence_effect(seq); + + for(icu= seq->ipo->curve.first; icu; icu= icu->next) { + sh.store_icu_yrange(seq, icu->adrcode, &icu->ymin, &icu->ymax); + } +} + + +static int seq_is_parent(Sequence *par, Sequence *seq) +{ + return ((par->seq1 == seq) || (par->seq2 == seq) || (par->seq3 == seq)); +} + +static int seq_is_predecessor(Sequence *pred, Sequence *seq) +{ + if (!pred) return 0; + if(pred == seq) return 0; + else if(seq_is_parent(pred, seq)) return 1; + else if(pred->seq1 && seq_is_predecessor(pred->seq1, seq)) return 1; + else if(pred->seq2 && seq_is_predecessor(pred->seq2, seq)) return 1; + else if(pred->seq3 && seq_is_predecessor(pred->seq3, seq)) return 1; + + return 0; +} + +void deselect_all_seq(Scene *scene) +{ + Sequence *seq; + Editing *ed= seq_give_editing(scene, FALSE); + + + if(ed==NULL) return; + + SEQP_BEGIN(ed, seq) { + seq->flag &= SEQ_DESEL; + } + SEQ_END + +} + +void recurs_sel_seq(Sequence *seqm) +{ + Sequence *seq; + + seq= seqm->seqbase.first; + while(seq) { + + if(seqm->flag & (SEQ_LEFTSEL+SEQ_RIGHTSEL)) seq->flag &= SEQ_DESEL; + else if(seqm->flag & SELECT) seq->flag |= SELECT; + else seq->flag &= SEQ_DESEL; + + if(seq->seqbase.first) recurs_sel_seq(seq); + + seq= seq->next; + } +} + +Sequence *alloc_sequence(ListBase *lb, int cfra, int machine) +{ + Sequence *seq; + + /*ed= scene->ed;*/ + + seq= MEM_callocN( sizeof(Sequence), "addseq"); + BLI_addtail(lb, seq); + + //set_last_seq(scene, seq); // Probably not a great idea at such a low level anyway - Campbell + + *( (short *)seq->name )= ID_SEQ; + seq->name[2]= 0; + + seq->flag= SELECT; + seq->start= cfra; + seq->machine= machine; + seq->mul= 1.0; + seq->blend_opacity = 100.0; + + return seq; +} + +int event_to_efftype(int event) +{ + if(event==2) return SEQ_CROSS; + if(event==3) return SEQ_GAMCROSS; + if(event==4) return SEQ_ADD; + if(event==5) return SEQ_SUB; + if(event==6) return SEQ_MUL; + if(event==7) return SEQ_ALPHAOVER; + if(event==8) return SEQ_ALPHAUNDER; + if(event==9) return SEQ_OVERDROP; + if(event==10) return SEQ_PLUGIN; + if(event==13) return SEQ_WIPE; + if(event==14) return SEQ_GLOW; + if(event==15) return SEQ_TRANSFORM; + if(event==16) return SEQ_COLOR; + if(event==17) return SEQ_SPEED; + return 0; +} + +#if 0 +static void reload_sound_strip(Scene *scene, char *name) +{ + Editing *ed; + Sequence *seq, *seqact; + SpaceFile *sfile; + Sequence *last_seq= get_last_seq(scene); + + ed= scene->ed; + + if(last_seq==0 || last_seq->type!=SEQ_SOUND) return; + seqact= last_seq; /* last_seq changes in alloc_sequence */ + + /* search sfile */ +// sfile= scrarea_find_space_of_type(curarea, SPACE_FILE); + if(sfile==0) return; + + waitcursor(1); + + seq = sfile_to_snd_sequence(sfile, seqact->start, seqact->machine); + printf("seq->type: %i\n", seq->type); + if(seq && seq!=seqact) { + /* i'm not sure about this one, seems to work without it -- sgefant */ + seq_free_strip(seqact->strip); + + seqact->strip= seq->strip; + + seqact->len= seq->len; + calc_sequence(seqact); + + seq->strip= 0; + seq_free_sequence(ed, seq); + BLI_remlink(ed->seqbasep, seq); + + seq= ed->seqbasep->first; + + } + + waitcursor(0); + +} +#endif + +static void reload_image_strip(Scene *scene, char *name) +{ + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq=NULL, *seqact; + SpaceFile *sfile=NULL; + Sequence *last_seq= get_last_seq(scene); + + + + if(last_seq==0 || last_seq->type!=SEQ_IMAGE) return; + seqact= last_seq; /* last_seq changes in alloc_sequence */ + + /* search sfile */ +// sfile= scrarea_find_space_of_type(curarea, SPACE_FILE); + if(sfile==0) return; + + waitcursor(1); + +// seq= sfile_to_sequence(scene, sfile, seqact->start, seqact->machine, 1); // XXX ADD BACK + if(seq && seq!=seqact) { + seq_free_strip(seqact->strip); + + seqact->strip= seq->strip; + + seqact->len= seq->len; + calc_sequence(seqact); + + seq->strip= 0; + seq_free_sequence(ed, seq); + BLI_remlink(ed->seqbasep, seq); + + update_changed_seq_and_deps(scene, seqact, 1, 1); + } + waitcursor(0); + +} + + +void change_sequence(Scene *scene) +{ + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *last_seq= get_last_seq(scene); + Scene *sce; + short event; + + if(last_seq==0) return; + + if(last_seq->type & SEQ_EFFECT) { + event = pupmenu("Change Effect%t" + "|Switch A <-> B %x1" + "|Switch B <-> C %x10" + "|Plugin%x11" + "|Recalculate%x12" + "|Cross%x2" + "|Gamma Cross%x3" + "|Add%x4" + "|Sub%x5" + "|Mul%x6" + "|Alpha Over%x7" + "|Alpha Under%x8" + "|Alpha Over Drop%x9" + "|Wipe%x13" + "|Glow%x14" + "|Transform%x15" + "|Color Generator%x16" + "|Speed Control%x17"); + if(event > 0) { + if(event==1) { + SWAP(Sequence *,last_seq->seq1,last_seq->seq2); + } + else if(event==10) { + SWAP(Sequence *,last_seq->seq2,last_seq->seq3); + } + else if(event==11) { + activate_fileselect( + FILE_SPECIAL, "Select Plugin", + U.plugseqdir, change_plugin_seq); + } + else if(event==12); + /* recalculate: only new_stripdata */ + else { + /* free previous effect and init new effect */ + struct SeqEffectHandle sh; + + if (get_sequence_effect_num_inputs( + last_seq->type) + < get_sequence_effect_num_inputs( + event_to_efftype(event))) { + error("New effect needs more " + "input strips!"); + } else { + sh = get_sequence_effect(last_seq); + sh.free(last_seq); + + last_seq->type + = event_to_efftype(event); + + sh = get_sequence_effect(last_seq); + sh.init(last_seq); + } + } + + update_changed_seq_and_deps(scene, last_seq, 0, 1); + } + } + else if(last_seq->type == SEQ_IMAGE) { + if(okee("Change images")) { + activate_fileselect(FILE_SPECIAL, + "Select Images", + ed->act_imagedir, + reload_image_strip); + } + } + else if(last_seq->type == SEQ_MOVIE) { + ; + } + else if(last_seq->type == SEQ_SCENE) { + event= pupmenu("Change Scene%t|Update Start and End"); + + if(event==1) { + sce= last_seq->scene; + + last_seq->len= sce->r.efra - sce->r.sfra + 1; + last_seq->sfra= sce->r.sfra; + + /* bad code to change seq->len? update_changed_seq_and_deps() expects the strip->len to be OK */ + new_tstripdata(last_seq); + + update_changed_seq_and_deps(scene, last_seq, 1, 1); + + } + } + +} + +int seq_effect_find_selected(Scene *scene, Sequence *activeseq, int type, Sequence **selseq1, Sequence **selseq2, Sequence **selseq3, char **error_str) +{ + Editing *ed = seq_give_editing(scene, FALSE); + Sequence *seq1= 0, *seq2= 0, *seq3= 0, *seq; + + *error_str= NULL; + + if (!activeseq) + seq2= get_last_seq(scene); + + for(seq=ed->seqbasep->first; seq; seq=seq->next) { + if(seq->flag & SELECT) { + if (seq->type == SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND) { + *error_str= "Can't apply effects to audio sequence strips"; + return 0; + } + if((seq != activeseq) && (seq != seq2)) { + if(seq2==0) seq2= seq; + else if(seq1==0) seq1= seq; + else if(seq3==0) seq3= seq; + else { + *error_str= "Can't apply effect to more than 3 sequence strips"; + return 0; + } + } + } + } + + /* make sequence selection a little bit more intuitive + for 3 strips: the last-strip should be sequence3 */ + if (seq3 != 0 && seq2 != 0) { + Sequence *tmp = seq2; + seq2 = seq3; + seq3 = tmp; + } + + + switch(get_sequence_effect_num_inputs(type)) { + case 0: + *selseq1 = *selseq2 = *selseq3 = 0; + return 1; /* succsess */ + case 1: + if(seq2==0) { + *error_str= "Need at least one selected sequence strip"; + return 0; + } + if(seq1==0) seq1= seq2; + if(seq3==0) seq3= seq2; + case 2: + if(seq1==0 || seq2==0) { + *error_str= "Need 2 selected sequence strips"; + return 0; + } + if(seq3==0) seq3= seq2; + } + + if (seq1==NULL && seq2==NULL && seq3==NULL) { + *error_str= "TODO: in what cases does this happen?"; + return 0; + } + + *selseq1= seq1; + *selseq2= seq2; + *selseq3= seq3; + + return 1; +} + +void reassign_inputs_seq_effect(Scene *scene) +{ + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq1, *seq2, *seq3, *last_seq = get_last_seq(scene); + char *error_msg; + + if(last_seq==0 || !(last_seq->type & SEQ_EFFECT)) return; + if(ed==NULL) return; + + if(!seq_effect_find_selected(scene, last_seq, last_seq->type, &seq1, &seq2, &seq3, &error_msg)) { + //BKE_report(op->reports, RPT_ERROR, error_msg); // XXX operatorify + return; + } + /* see reassigning would create a cycle */ + if( seq_is_predecessor(seq1, last_seq) || + seq_is_predecessor(seq2, last_seq) || + seq_is_predecessor(seq3, last_seq) + ) { + //BKE_report(op->reports, RPT_ERROR, "Can't reassign inputs: no cycles allowed"); // XXX operatorify + return; + } + + last_seq->seq1 = seq1; + last_seq->seq2 = seq2; + last_seq->seq3 = seq3; + + update_changed_seq_and_deps(scene, last_seq, 1, 1); + +} + +static Sequence *del_seq_find_replace_recurs(Scene *scene, Sequence *seq) +{ + Sequence *seq1, *seq2, *seq3; + + /* try to find a replacement input sequence, and flag for later deletion if + no replacement can be found */ + + if(!seq) + return NULL; + else if(!(seq->type & SEQ_EFFECT)) + return ((seq->flag & SELECT)? NULL: seq); + else if(!(seq->flag & SELECT)) { + /* try to find replacement for effect inputs */ + seq1= del_seq_find_replace_recurs(scene, seq->seq1); + seq2= del_seq_find_replace_recurs(scene, seq->seq2); + seq3= del_seq_find_replace_recurs(scene, seq->seq3); + + if(seq1==seq->seq1 && seq2==seq->seq2 && seq3==seq->seq3); + else if(seq1 || seq2 || seq3) { + seq->seq1= (seq1)? seq1: (seq2)? seq2: seq3; + seq->seq2= (seq2)? seq2: (seq1)? seq1: seq3; + seq->seq3= (seq3)? seq3: (seq1)? seq1: seq2; + + update_changed_seq_and_deps(scene, seq, 1, 1); + } + else + seq->flag |= SELECT; /* mark for delete */ + } + + if (seq->flag & SELECT) { + if((seq1 = del_seq_find_replace_recurs(scene, seq->seq1))) return seq1; + if((seq2 = del_seq_find_replace_recurs(scene, seq->seq2))) return seq2; + if((seq3 = del_seq_find_replace_recurs(scene, seq->seq3))) return seq3; + else return NULL; + } + else + return seq; +} + +static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short deleteall) +{ + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq, *seqn; + Sequence *last_seq = get_last_seq(scene); + + seq= lb->first; + while(seq) { + seqn= seq->next; + if((seq->flag & flag) || deleteall) { + if(seq->type==SEQ_RAM_SOUND && seq->sound) + seq->sound->id.us--; + + BLI_remlink(lb, seq); + if(seq==last_seq) set_last_seq(scene, NULL); + if(seq->type==SEQ_META) recurs_del_seq_flag(scene, &seq->seqbase, flag, 1); + if(seq->ipo) seq->ipo->id.us--; + seq_free_sequence(ed, seq); + } + seq= seqn; + } +} + +static Sequence *dupli_seq(Sequence *seq) +{ + Sequence *seqn = MEM_dupallocN(seq); + // XXX animato: ID *id; + + seq->tmp = seqn; + + seqn->strip= MEM_dupallocN(seq->strip); + + // XXX animato +#if 0 + if (seqn->ipo) { + if (U.dupflag & USER_DUP_IPO) { + id= (ID *)seqn->ipo; + seqn->ipo= copy_ipo(seqn->ipo); + /* we don't need to decrease the number + * of the ipo because we never increase it, + * for example, adduplicate need decrease + * the number but only because copy_object + * call id_us_plus for the ipo block and + * single_ipo_users only work if id->us > 1. + * + * need call ipo_idnew here, for drivers ?? + * - Diego + */ + } + else + seqn->ipo->id.us++; + } +#endif + + seqn->strip->tstripdata = 0; + seqn->strip->tstripdata_startstill = 0; + seqn->strip->tstripdata_endstill = 0; + seqn->strip->ibuf_startstill = 0; + seqn->strip->ibuf_endstill = 0; + + if (seq->strip->crop) { + seqn->strip->crop = MEM_dupallocN(seq->strip->crop); + } + + if (seq->strip->transform) { + seqn->strip->transform = MEM_dupallocN(seq->strip->transform); + } + + if (seq->strip->proxy) { + seqn->strip->proxy = MEM_dupallocN(seq->strip->proxy); + } + + if (seq->strip->color_balance) { + seqn->strip->color_balance + = MEM_dupallocN(seq->strip->color_balance); + } + + if(seq->type==SEQ_META) { + seqn->strip->stripdata = 0; + + seqn->seqbase.first= seqn->seqbase.last= 0; + /* WATCH OUT!!! - This metastrip is not recursively duplicated here - do this after!!! */ + /* - recurs_dupli_seq(&seq->seqbase,&seqn->seqbase);*/ + } else if(seq->type == SEQ_SCENE) { + seqn->strip->stripdata = 0; + } else if(seq->type == SEQ_MOVIE) { + seqn->strip->stripdata = + MEM_dupallocN(seq->strip->stripdata); + seqn->anim= 0; + } else if(seq->type == SEQ_RAM_SOUND) { + seqn->strip->stripdata = + MEM_dupallocN(seq->strip->stripdata); + seqn->sound->id.us++; + } else if(seq->type == SEQ_HD_SOUND) { + seqn->strip->stripdata = + MEM_dupallocN(seq->strip->stripdata); + seqn->hdaudio = 0; + } else if(seq->type == SEQ_IMAGE) { + seqn->strip->stripdata = + MEM_dupallocN(seq->strip->stripdata); + } else if(seq->type >= SEQ_EFFECT) { + if(seq->seq1 && seq->seq1->tmp) seqn->seq1= seq->seq1->tmp; + if(seq->seq2 && seq->seq2->tmp) seqn->seq2= seq->seq2->tmp; + if(seq->seq3 && seq->seq3->tmp) seqn->seq3= seq->seq3->tmp; + + if (seq->type & SEQ_EFFECT) { + struct SeqEffectHandle sh; + sh = get_sequence_effect(seq); + if(sh.copy) + sh.copy(seq, seqn); + } + + seqn->strip->stripdata = 0; + + } else { + fprintf(stderr, "Aiiiiekkk! sequence type not " + "handled in duplicate!\nExpect a crash" + " now...\n"); + } + + return seqn; +} + +static Sequence * deep_dupli_seq(Sequence * seq) +{ + Sequence * seqn = dupli_seq(seq); + if (seq->type == SEQ_META) { + Sequence * s; + for(s= seq->seqbase.first; s; s = s->next) { + Sequence * n = deep_dupli_seq(s); + if (n) { + BLI_addtail(&seqn->seqbase, n); + } + } + } + return seqn; +} + + +static void recurs_dupli_seq(Scene *scene, ListBase *old, ListBase *new) +{ + Sequence *seq; + Sequence *seqn = 0; + Sequence *last_seq = get_last_seq(scene); + + for(seq= old->first; seq; seq= seq->next) { + seq->tmp= NULL; + if(seq->flag & SELECT) { + seqn = dupli_seq(seq); + if (seqn) { /*should never fail */ + seq->flag &= SEQ_DESEL; + seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL+SEQ_LOCK); + + BLI_addtail(new, seqn); + if(seq->type==SEQ_META) + recurs_dupli_seq(scene, &seq->seqbase,&seqn->seqbase); + + if (seq == last_seq) { + set_last_seq(scene, seqn); + } + } + } + } +} + +static Sequence *cut_seq_hard(Scene *scene, Sequence * seq, int cutframe) +{ + TransSeq ts; + Sequence *seqn = 0; + int skip_dup = FALSE; + + /* backup values */ + ts.start= seq->start; + ts.machine= seq->machine; + ts.startstill= seq->startstill; + ts.endstill= seq->endstill; + ts.startdisp= seq->startdisp; + ts.enddisp= seq->enddisp; + ts.startofs= seq->anim_startofs; + ts.endofs= seq->anim_endofs; + ts.len= seq->len; + + /* First Strip! */ + /* strips with extended stillfames before */ + + if ((seq->startstill) && (cutframe <seq->start)) { + /* don't do funny things with METAs ... */ + if (seq->type == SEQ_META) { + skip_dup = TRUE; + seq->startstill = seq->start - cutframe; + } else { + seq->start= cutframe -1; + seq->startstill= cutframe -seq->startdisp -1; + seq->anim_endofs += seq->len - 1; + seq->endstill= 0; + } + } + /* normal strip */ + else if ((cutframe >=seq->start)&&(cutframe <=(seq->start+seq->len))) { + seq->endofs = 0; + seq->endstill = 0; + seq->anim_endofs += (seq->start+seq->len) - cutframe; + } + /* strips with extended stillframes after */ + else if (((seq->start+seq->len) < cutframe) && (seq->endstill)) { + seq->endstill -= seq->enddisp - cutframe; + /* don't do funny things with METAs ... */ + if (seq->type == SEQ_META) { + skip_dup = TRUE; + } + } + + reload_sequence_new_file(scene, seq); + calc_sequence(seq); + + if (!skip_dup) { + /* Duplicate AFTER the first change */ + seqn = deep_dupli_seq(seq); + } + + if (seqn) { + seqn->flag |= SELECT; + + /* Second Strip! */ + /* strips with extended stillframes before */ + if ((seqn->startstill) && (cutframe == seqn->start + 1)) { + seqn->start = ts.start; + seqn->startstill= ts.start- cutframe; + seqn->anim_endofs = ts.endofs; + seqn->endstill = ts.endstill; + } + + /* normal strip */ + else if ((cutframe>=seqn->start)&&(cutframe<=(seqn->start+seqn->len))) { + seqn->start = cutframe; + seqn->startstill = 0; + seqn->startofs = 0; + seqn->anim_startofs += cutframe - ts.start; + seqn->anim_endofs = ts.endofs; + seqn->endstill = ts.endstill; + } + + /* strips with extended stillframes after */ + else if (((seqn->start+seqn->len) < cutframe) && (seqn->endstill)) { + seqn->start = cutframe; + seqn->startofs = 0; + seqn->anim_startofs += ts.len-1; + seqn->endstill = ts.enddisp - cutframe -1; + seqn->startstill = 0; + } + + reload_sequence_new_file(scene, seqn); + calc_sequence(seqn); + } + return seqn; +} + +static Sequence *cut_seq_soft(Scene *scene, Sequence * seq, int cutframe) +{ + TransSeq ts; + Sequence *seqn = 0; + int skip_dup = FALSE; + + /* backup values */ + ts.start= seq->start; + ts.machine= seq->machine; + ts.startstill= seq->startstill; + ts.endstill= seq->endstill; + ts.startdisp= seq->startdisp; + ts.enddisp= seq->enddisp; + ts.startofs= seq->startofs; + ts.endofs= seq->endofs; + ts.len= seq->len; + + /* First Strip! */ + /* strips with extended stillfames before */ + + if ((seq->startstill) && (cutframe <seq->start)) { + /* don't do funny things with METAs ... */ + if (seq->type == SEQ_META) { + skip_dup = TRUE; + seq->startstill = seq->start - cutframe; + } else { + seq->start= cutframe -1; + seq->startstill= cutframe -seq->startdisp -1; + seq->endofs = seq->len - 1; + seq->endstill= 0; + } + } + /* normal strip */ + else if ((cutframe >=seq->start)&&(cutframe <=(seq->start+seq->len))) { + seq->endofs = (seq->start+seq->len) - cutframe; + } + /* strips with extended stillframes after */ + else if (((seq->start+seq->len) < cutframe) && (seq->endstill)) { + seq->endstill -= seq->enddisp - cutframe; + /* don't do funny things with METAs ... */ + if (seq->type == SEQ_META) { + skip_dup = TRUE; + } + } + + calc_sequence(seq); + + if (!skip_dup) { + /* Duplicate AFTER the first change */ + seqn = deep_dupli_seq(seq); + } + + if (seqn) { + seqn->flag |= SELECT; + + /* Second Strip! */ + /* strips with extended stillframes before */ + if ((seqn->startstill) && (cutframe == seqn->start + 1)) { + seqn->start = ts.start; + seqn->startstill= ts.start- cutframe; + seqn->endofs = ts.endofs; + seqn->endstill = ts.endstill; + } + + /* normal strip */ + else if ((cutframe>=seqn->start)&&(cutframe<=(seqn->start+seqn->len))) { + seqn->startstill = 0; + seqn->startofs = cutframe - ts.start; + seqn->endofs = ts.endofs; + seqn->endstill = ts.endstill; + } + + /* strips with extended stillframes after */ + else if (((seqn->start+seqn->len) < cutframe) && (seqn->endstill)) { + seqn->start = cutframe - ts.len +1; + seqn->startofs = ts.len-1; + seqn->endstill = ts.enddisp - cutframe -1; + seqn->startstill = 0; + } + + calc_sequence(seqn); + } + return seqn; +} + + +/* like duplicate, but only duplicate and cut overlapping strips, + * strips to the left of the cutframe are ignored and strips to the right are moved into the new list */ +static int cut_seq_list(Scene *scene, ListBase *old, ListBase *new, int cutframe, + Sequence * (*cut_seq)(Scene *, Sequence *, int)) +{ + int did_something = FALSE; + Sequence *seq, *seq_next; + + seq= old->first; + + while(seq) { + seq_next = seq->next; /* we need this because we may remove seq */ + + seq->tmp= NULL; + if(seq->flag & SELECT) { + if(cutframe > seq->startdisp && + cutframe < seq->enddisp) { + Sequence * seqn = cut_seq(scene, seq, cutframe); + if (seqn) { + BLI_addtail(new, seqn); + } + did_something = TRUE; + } else if (seq->enddisp <= cutframe) { + /* do nothing */ + } else if (seq->startdisp >= cutframe) { + /* move into new list */ + BLI_remlink(old, seq); + BLI_addtail(new, seq); + } + } + seq = seq_next; + } + return did_something; +} + +int insert_gap(Scene *scene, int gap, int cfra) +{ + Sequence *seq; + Editing *ed= seq_give_editing(scene, FALSE); + int done=0; + + /* all strips >= cfra are shifted */ + + if(ed==NULL) return 0; + + SEQP_BEGIN(ed, seq) { + if(seq->startdisp >= cfra) { + seq->start+= gap; + calc_sequence(seq); + done= 1; + } + } + SEQ_END + + return done; +} + +void touch_seq_files(Scene *scene) +{ + Sequence *seq; + Editing *ed= seq_give_editing(scene, FALSE); + char str[256]; + + /* touch all strips with movies */ + + if(ed==NULL) return; + + if(okee("Touch and print selected movies")==0) return; + + waitcursor(1); + + SEQP_BEGIN(ed, seq) { + if(seq->flag & SELECT) { + if(seq->type==SEQ_MOVIE) { + if(seq->strip && seq->strip->stripdata) { + BLI_make_file_string(G.sce, str, seq->strip->dir, seq->strip->stripdata->name); + BLI_touch(seq->name); + } + } + + } + } + SEQ_END + + waitcursor(0); +} + +void set_filter_seq(Scene *scene) +{ + Sequence *seq; + Editing *ed= seq_give_editing(scene, FALSE); + + + if(ed==NULL) return; + + if(okee("Set Deinterlace")==0) return; + + SEQP_BEGIN(ed, seq) { + if(seq->flag & SELECT) { + if(seq->type==SEQ_MOVIE) { + seq->flag |= SEQ_FILTERY; + reload_sequence_new_file(scene, seq); + } + + } + } + SEQ_END + +} + +void seq_remap_paths(Scene *scene) +{ + Sequence *seq, *last_seq = get_last_seq(scene); + Editing *ed= seq_give_editing(scene, FALSE); + char from[FILE_MAX], to[FILE_MAX], stripped[FILE_MAX]; + + + if(last_seq==NULL) + return; + + BLI_strncpy(from, last_seq->strip->dir, FILE_MAX); +// XXX if (0==sbutton(from, 0, sizeof(from)-1, "From: ")) +// return; + + strcpy(to, from); +// XXX if (0==sbutton(to, 0, sizeof(to)-1, "To: ")) +// return; + + if (strcmp(to, from)==0) + return; + + SEQP_BEGIN(ed, seq) { + if(seq->flag & SELECT) { + if(strncmp(seq->strip->dir, from, strlen(from))==0) { + printf("found %s\n", seq->strip->dir); + + /* strip off the beginning */ + stripped[0]= 0; + BLI_strncpy(stripped, seq->strip->dir + strlen(from), FILE_MAX); + + /* new path */ + BLI_strncpy(seq->strip->dir, to, FILE_MAX); + strcat(seq->strip->dir, stripped); + printf("new %s\n", seq->strip->dir); + } + } + } + SEQ_END + +} + + +void no_gaps(Scene *scene) +{ + Editing *ed= seq_give_editing(scene, FALSE); + int cfra, first= 0, done; + + + if(ed==NULL) return; + + for(cfra= CFRA; cfra<=EFRA; cfra++) { + if(first==0) { + if( evaluate_seq_frame(scene, cfra) ) first= 1; + } + else { + done= 1; + while( evaluate_seq_frame(scene, cfra) == 0) { + done= insert_gap(scene, -1, cfra); + if(done==0) break; + } + if(done==0) break; + } + } + +} + +#if 0 +static int seq_get_snaplimit(View2D *v2d) +{ + /* fake mouse coords to get the snap value + a bit lazy but its only done once pre transform */ + float xmouse, ymouse, x; + short mval[2] = {24, 0}; /* 24 screen px snap */ + + UI_view2d_region_to_view(v2d, mval[0], mval[1], &xmouse, &ymouse); + x = xmouse; + mval[0] = 0; + UI_view2d_region_to_view(v2d, mval[0], mval[1], &xmouse, &ymouse); + return (int)(x - xmouse); +} +#endif + +void seq_snap(Scene *scene, short event) +{ + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq; + + + if(ed==NULL) return; + + /* problem: contents of meta's are all shifted to the same position... */ + + /* also check metas */ + SEQP_BEGIN(ed, seq) { + if (seq->flag & SELECT && !(seq->depth==0 && seq->flag & SEQ_LOCK) && + seq_tx_test(seq)) { + if((seq->flag & (SEQ_LEFTSEL+SEQ_RIGHTSEL))==0) { + seq->start= CFRA-seq->startofs+seq->startstill; + } else { + if(seq->flag & SEQ_LEFTSEL) { + seq_tx_set_final_left(seq, CFRA); + } else { /* SEQ_RIGHTSEL */ + seq_tx_set_final_right(seq, CFRA); + } + seq_tx_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL); + } + calc_sequence(seq); + } + } + SEQ_END + + /* test for effects and overlap */ + SEQP_BEGIN(ed, seq) { + if(seq->flag & SELECT && !(seq->depth==0 && seq->flag & SEQ_LOCK)) { + seq->flag &= ~SEQ_OVERLAP; + if( seq_test_overlap(ed->seqbasep, seq) ) { + shuffle_seq(ed->seqbasep, seq); + } + } + else if(seq->type & SEQ_EFFECT) { + if(seq->seq1 && (seq->seq1->flag & SELECT)) + calc_sequence(seq); + else if(seq->seq2 && (seq->seq2->flag & SELECT)) + calc_sequence(seq); + else if(seq->seq3 && (seq->seq3->flag & SELECT)) + calc_sequence(seq); + } + } + SEQ_END; + + /* as last: */ + sort_seq(scene); + +} + +void seq_snap_menu(Scene *scene) +{ + short event; + + event= pupmenu("Snap %t|To Current Frame%x1"); + if(event < 1) return; + + seq_snap(scene, event); +} + +/* Operator functions */ + +static int sequencer_mute_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq; + int selected; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + selected= RNA_enum_is_equal(op->ptr, "type", "SELECTED"); + + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + if ((seq->flag & SEQ_LOCK)==0) { + if(selected){ /* mute unselected */ + if (seq->flag & SELECT) { + seq->flag |= SEQ_MUTE; + } + } + else { + if ((seq->flag & SELECT)==0) { + seq->flag |= SEQ_MUTE; + } + } + } + } + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_mute(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Mute Strips"; + ot->idname= "SEQUENCER_OT_mute"; + + /* api callbacks */ + ot->exec= sequencer_mute_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "type", sequencer_prop_operate_types, SEQ_SELECTED, "Type", ""); +} + + +/* unmute operator */ +static int sequencer_unmute_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq; + int selected; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + selected= RNA_enum_is_equal(op->ptr, "type", "SELECTED"); + + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + if ((seq->flag & SEQ_LOCK)==0) { + if(selected){ /* unmute unselected */ + if (seq->flag & SELECT) { + seq->flag &= ~SEQ_MUTE; + } + } + else { + if ((seq->flag & SELECT)==0) { + seq->flag &= ~SEQ_MUTE; + } + } + } + } + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_unmute(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "UnMute Strips"; + ot->idname= "SEQUENCER_OT_unmute"; + + /* api callbacks */ + ot->exec= sequencer_unmute_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "type", sequencer_prop_operate_types, SEQ_SELECTED, "Type", ""); +} + + +/* lock operator */ +static int sequencer_lock_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + if (seq->flag & SELECT) { + seq->flag |= SEQ_LOCK; + } + } + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_lock(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Lock Strips"; + ot->idname= "SEQUENCER_OT_lock"; + + /* api callbacks */ + ot->exec= sequencer_lock_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* unlock operator */ +static int sequencer_unlock_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + if (seq->flag & SELECT) { + seq->flag &= ~SEQ_LOCK; + } + } + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_unlock(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "UnLock Strips"; + ot->idname= "SEQUENCER_OT_unlock"; + + /* api callbacks */ + ot->exec= sequencer_unlock_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* reload operator */ +static int sequencer_reload_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + if(seq->flag & SELECT) { + update_changed_seq_and_deps(scene, seq, 0, 1); + } + } + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_reload(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Reload Strips"; + ot->idname= "SEQUENCER_OT_reload"; + + /* api callbacks */ + ot->exec= sequencer_reload_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* reload operator */ +static int sequencer_refresh_all_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + + if(ed==NULL) + return OPERATOR_CANCELLED; + + free_imbuf_seq(&ed->seqbase); + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_refresh_all(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Refresh Sequencer"; + ot->idname= "SEQUENCER_OT_refresh_all"; + + /* api callbacks */ + ot->exec= sequencer_refresh_all_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* cut operator */ +static EnumPropertyItem prop_cut_types[] = { + {SEQ_CUT_SOFT, "SOFT", "Soft", ""}, + {SEQ_CUT_HARD, "HARD", "Hard", ""}, + {0, NULL, NULL, NULL} +}; + +static int sequencer_cut_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + int cut_side, cut_hard, cut_frame; + + ListBase newlist; + int changed; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + cut_frame= RNA_int_get(op->ptr, "frame"); + cut_hard= RNA_enum_get(op->ptr, "type"); + cut_side= RNA_enum_get(op->ptr, "side"); + + newlist.first= newlist.last= NULL; + + if (cut_hard==SEQ_CUT_HARD) { + changed = cut_seq_list(scene, + ed->seqbasep, &newlist, cut_frame, cut_seq_hard); + } else { + changed = cut_seq_list(scene, + ed->seqbasep, &newlist, cut_frame, cut_seq_soft); + } + + if (newlist.first) { /* got new strips ? */ + Sequence *seq; + addlisttolist(ed->seqbasep, &newlist); + + if (cut_side != SEQ_SIDE_BOTH) { + SEQP_BEGIN(ed, seq) { + if (cut_side==SEQ_SIDE_LEFT) { + if ( seq->startdisp >= cut_frame ) { + seq->flag &= SEQ_DESEL; + } + } else { + if ( seq->enddisp <= cut_frame ) { + seq->flag &= SEQ_DESEL; + } + } + } + SEQ_END; + } + /* as last: */ + sort_seq(scene); + } + + if (changed) { + ED_area_tag_redraw(CTX_wm_area(C)); + } + + return OPERATOR_FINISHED; +} + + +static int sequencer_cut_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + Scene *scene = CTX_data_scene(C); + ARegion *ar= CTX_wm_region(C); + View2D *v2d= UI_view2d_fromcontext(C); + + int cut_side, cut_frame; + + cut_frame= CFRA; + cut_side= mouse_frame_side(v2d, event->x - ar->winrct.xmin, cut_frame); + + RNA_int_set(op->ptr, "frame", cut_frame); + RNA_enum_set(op->ptr, "side", cut_side); + /*RNA_enum_set(op->ptr, "type", cut_hard); */ /*This type is set from the key shortcut */ + + return sequencer_cut_exec(C, op); +} + + +void SEQUENCER_OT_cut(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Cut Strips"; + ot->idname= "SEQUENCER_OT_cut"; + + /* api callbacks */ + ot->invoke= sequencer_cut_invoke; + ot->exec= sequencer_cut_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_int(ot->srna, "frame", 0, INT_MIN, INT_MAX, "Frame", "Frame where selected strips will be cut", INT_MIN, INT_MAX); + RNA_def_enum(ot->srna, "type", prop_cut_types, SEQ_CUT_SOFT, "Type", "the type of cut operation to perform on strips"); + RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side that remains selected after cutting"); +} + +/* duplicate operator */ +static int sequencer_add_duplicate_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + + ListBase new= {NULL, NULL}; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + recurs_dupli_seq(scene, ed->seqbasep, &new); + addlisttolist(ed->seqbasep, &new); + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + +static int sequencer_add_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + sequencer_add_duplicate_exec(C, op); + + RNA_int_set(op->ptr, "mode", TFM_TRANSLATION); + WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_duplicate_add(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Add Duplicate"; + ot->idname= "SEQUENCER_OT_duplicate_add"; + + /* api callbacks */ + ot->invoke= sequencer_add_duplicate_invoke; + ot->exec= sequencer_add_duplicate_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* to give to transform */ + RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX); +} + +/* delete operator */ +static int sequencer_delete_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq; + MetaStack *ms; + int nothingSelected = TRUE; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + seq=get_last_seq(scene); + if (seq && seq->flag & SELECT) { /* avoid a loop since this is likely to be selected */ + nothingSelected = FALSE; + } else { + for (seq = ed->seqbasep->first; seq; seq = seq->next) { + if (seq->flag & SELECT) { + nothingSelected = FALSE; + break; + } + } + } + + if (nothingSelected) + return OPERATOR_FINISHED; + + /* free imbufs of all dependent strips */ + for(seq=ed->seqbasep->first; seq; seq=seq->next) + if(seq->flag & SELECT) + update_changed_seq_and_deps(scene, seq, 1, 0); + + /* for effects, try to find a replacement input */ + for(seq=ed->seqbasep->first; seq; seq=seq->next) + if((seq->type & SEQ_EFFECT) && !(seq->flag & SELECT)) + del_seq_find_replace_recurs(scene, seq); + + /* delete all selected strips */ + recurs_del_seq_flag(scene, ed->seqbasep, SELECT, 0); + + /* updates lengths etc */ + seq= ed->seqbasep->first; + while(seq) { + calc_sequence(seq); + seq= seq->next; + } + + /* free parent metas */ + ms= ed->metastack.last; + while(ms) { + ms->parseq->strip->len= 0; /* force new alloc */ + calc_sequence(ms->parseq); + ms= ms->prev; + } + + //ED_area_tag_redraw(CTX_wm_area(C)); + WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER, NULL); /* redraw other sequencer views */ + + return OPERATOR_FINISHED; +} + + +void SEQUENCER_OT_delete(wmOperatorType *ot) +{ + + /* identifiers */ + ot->name= "Erase Strips"; + ot->idname= "SEQUENCER_OT_delete"; + + /* api callbacks */ + ot->invoke= WM_operator_confirm; + ot->exec= sequencer_delete_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + + +/* separate_images operator */ +static int sequencer_separate_images_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + + Sequence *seq, *seq_new, *seq_next; + Strip *strip_new; + StripElem *se, *se_new; + int start_ofs, cfra, frame_end; + static int step= 1; + +// add_numbut(0, NUM|INT, "Image Duration:", 1, 256, &step, NULL); +// if (!do_clever_numbuts("Separate Images", 1, REDRAW)) +// return; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + seq= ed->seqbasep->first; + + while (seq) { + if((seq->flag & SELECT) && (seq->type == SEQ_IMAGE) && (seq->len > 1)) { + /* remove seq so overlap tests dont conflict, + see seq_free_sequence below for the real free'ing */ + seq_next = seq->next; + BLI_remlink(ed->seqbasep, seq); + if(seq->ipo) seq->ipo->id.us--; + + start_ofs = cfra = seq_tx_get_final_left(seq, 0); + frame_end = seq_tx_get_final_right(seq, 0); + + while (cfra < frame_end) { + /* new seq */ + se = give_stripelem(seq, cfra); + + seq_new= alloc_sequence(ed->seqbasep, start_ofs, seq->machine); + seq_new->type= SEQ_IMAGE; + seq_new->len = 1; + seq_new->endstill = step-1; + + /* new strip */ + seq_new->strip= strip_new= MEM_callocN(sizeof(Strip)*1, "strip"); + strip_new->len= 1; + strip_new->us= 1; + strncpy(strip_new->dir, seq->strip->dir, FILE_MAXDIR-1); + + /* new stripdata */ + strip_new->stripdata= se_new= MEM_callocN(sizeof(StripElem)*1, "stripelem"); + strncpy(se_new->name, se->name, FILE_MAXFILE-1); + calc_sequence(seq_new); + seq_new->flag &= ~SEQ_OVERLAP; + if (seq_test_overlap(ed->seqbasep, seq_new)) { + shuffle_seq(ed->seqbasep, seq_new); + } + + cfra++; + start_ofs += step; + } + + seq_free_sequence(ed, seq); + seq = seq->next; + } else { + seq = seq->next; + } + } + + /* as last: */ + sort_seq(scene); + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + + +void SEQUENCER_OT_images_separate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Separate Images"; + ot->idname= "SEQUENCER_OT_images_separate"; + + /* api callbacks */ + ot->invoke= WM_operator_confirm; + ot->exec= sequencer_separate_images_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + + +/* META Operators */ + +/* separate_meta_toggle operator */ +static int sequencer_meta_toggle_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *last_seq= get_last_seq(scene); + MetaStack *ms; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + if(last_seq && last_seq->type==SEQ_META && last_seq->flag & SELECT) { + /* Enter Metastrip */ + ms= MEM_mallocN(sizeof(MetaStack), "metastack"); + BLI_addtail(&ed->metastack, ms); + ms->parseq= last_seq; + ms->oldbasep= ed->seqbasep; + + ed->seqbasep= &last_seq->seqbase; + + set_last_seq(scene, NULL); + + } + else { + /* Exit Metastrip (if possible) */ + + Sequence *seq; + + if(ed->metastack.first==NULL) + return OPERATOR_CANCELLED; + + ms= ed->metastack.last; + BLI_remlink(&ed->metastack, ms); + + ed->seqbasep= ms->oldbasep; + + /* recalc all: the meta can have effects connected to it */ + for(seq= ed->seqbasep->first; seq; seq= seq->next) + calc_sequence(seq); + + set_last_seq(scene, ms->parseq); + + ms->parseq->flag |= SELECT; + recurs_sel_seq(ms->parseq); + + MEM_freeN(ms); + + } + + ED_area_tag_redraw(CTX_wm_area(C)); + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_meta_toggle(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Toggle Meta Strip"; + ot->idname= "SEQUENCER_OT_meta_toggle"; + + /* api callbacks */ + ot->exec= sequencer_meta_toggle_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + + +/* separate_meta_make operator */ +static int sequencer_meta_make_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + + Sequence *seq, *seqm, *next; + + int tot; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + /* is there more than 1 select */ + tot= 0; + seq= ed->seqbasep->first; + while(seq) { + if(seq->flag & SELECT) { + tot++; + if (seq->type == SEQ_RAM_SOUND) { + BKE_report(op->reports, RPT_ERROR, "Can't make Meta Strip from audio"); + return OPERATOR_CANCELLED;; + } + } + seq= seq->next; + } + if(tot < 1) return OPERATOR_CANCELLED;; + + + /* test relationships */ + seq= ed->seqbasep->first; + while(seq) { + if(seq->flag & SELECT) { + if(seq->type & SEQ_EFFECT) { + if(seq->seq1 && + (seq->seq1->flag & SELECT)==0) tot= 0; + if(seq->seq2 && + (seq->seq2->flag & SELECT)==0) tot= 0; + if(seq->seq3 && + (seq->seq3->flag & SELECT)==0) tot= 0; + } + } + else if(seq->type & SEQ_EFFECT) { + if(seq->seq1 && + (seq->seq1->flag & SELECT)) tot= 0; + if(seq->seq2 && + (seq->seq2->flag & SELECT)) tot= 0; + if(seq->seq3 && + (seq->seq3->flag & SELECT)) tot= 0; + } + if(tot==0) break; + seq= seq->next; + } + + if(tot==0) { + BKE_report(op->reports, RPT_ERROR, "Please select all related strips"); + return OPERATOR_CANCELLED; + } + + /* remove all selected from main list, and put in meta */ + + seqm= alloc_sequence(ed->seqbasep, 1, 1); + seqm->type= SEQ_META; + seqm->flag= SELECT; + + seq= ed->seqbasep->first; + while(seq) { + next= seq->next; + if(seq!=seqm && (seq->flag & SELECT)) { + BLI_remlink(ed->seqbasep, seq); + BLI_addtail(&seqm->seqbase, seq); + } + seq= next; + } + calc_sequence(seqm); + + seqm->strip= MEM_callocN(sizeof(Strip), "metastrip"); + seqm->strip->len= seqm->len; + seqm->strip->us= 1; + + set_last_seq(scene, seqm); + + if( seq_test_overlap(ed->seqbasep, seqm) ) shuffle_seq(ed->seqbasep, seqm); + + ED_area_tag_redraw(CTX_wm_area(C)); + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_meta_make(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Make Meta Strip"; + ot->idname= "SEQUENCER_OT_meta_make"; + + /* api callbacks */ + ot->invoke= WM_operator_confirm; + ot->exec= sequencer_meta_make_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + + +static int seq_depends_on_meta(Sequence *seq, Sequence *seqm) +{ + if (seq == seqm) return 1; + else if (seq->seq1 && seq_depends_on_meta(seq->seq1, seqm)) return 1; + else if (seq->seq2 && seq_depends_on_meta(seq->seq2, seqm)) return 1; + else if (seq->seq3 && seq_depends_on_meta(seq->seq3, seqm)) return 1; + else return 0; +} + +/* separate_meta_make operator */ +static int sequencer_meta_separate_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + + Sequence *seq, *last_seq = get_last_seq(scene); /* last_seq checks ed==NULL */ + + if(last_seq==NULL || last_seq->type!=SEQ_META) + return OPERATOR_CANCELLED; + + addlisttolist(ed->seqbasep, &last_seq->seqbase); + + last_seq->seqbase.first= 0; + last_seq->seqbase.last= 0; + + BLI_remlink(ed->seqbasep, last_seq); + seq_free_sequence(ed, last_seq); + + /* emtpy meta strip, delete all effects depending on it */ + for(seq=ed->seqbasep->first; seq; seq=seq->next) + if((seq->type & SEQ_EFFECT) && seq_depends_on_meta(seq, last_seq)) + seq->flag |= SEQ_FLAG_DELETE; + + recurs_del_seq_flag(scene, ed->seqbasep, SEQ_FLAG_DELETE, 0); + + /* test for effects and overlap */ + SEQP_BEGIN(ed, seq) { + if(seq->flag & SELECT) { + seq->flag &= ~SEQ_OVERLAP; + if( seq_test_overlap(ed->seqbasep, seq) ) { + shuffle_seq(ed->seqbasep, seq); + } + } + } + SEQ_END; + + sort_seq(scene); + + ED_area_tag_redraw(CTX_wm_area(C)); + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_meta_separate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "UnMeta Strip"; + ot->idname= "SEQUENCER_OT_meta_separate"; + + /* api callbacks */ + ot->invoke= WM_operator_confirm; + ot->exec= sequencer_meta_separate_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* view_all operator */ +static int sequencer_view_all_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + bScreen *sc= CTX_wm_screen(C); + ScrArea *area= CTX_wm_area(C); + ARegion *ar= CTX_wm_region(C); + SpaceSeq *sseq= area->spacedata.first; + View2D *v2d= UI_view2d_fromcontext(C); + + if (sseq->mainb==SEQ_DRAW_SEQUENCE) { + v2d->cur= v2d->tot; + UI_view2d_curRect_validate(v2d); + UI_view2d_sync(sc, area, v2d, V2D_LOCK_COPY); + } else { + /* Like zooming on an image view */ + float zoomX, zoomY; + int width, height, imgwidth, imgheight; + + width = ar->winx; + height = ar->winy; + + seq_reset_imageofs(sseq); + + imgwidth= (scene->r.size*scene->r.xsch)/100; + imgheight= (scene->r.size*scene->r.ysch)/100; + + /* Apply aspect, dosnt need to be that accurate */ + imgwidth= (int)(imgwidth * ((float)scene->r.xasp / (float)scene->r.yasp)); + + if (((imgwidth >= width) || (imgheight >= height)) && + ((width > 0) && (height > 0))) { + + /* Find the zoom value that will fit the image in the image space */ + zoomX = ((float)width) / ((float)imgwidth); + zoomY = ((float)height) / ((float)imgheight); + sseq->zoom= (zoomX < zoomY) ? zoomX : zoomY; + + sseq->zoom = 1.0f / power_of_2(1/ MIN2(zoomX, zoomY) ); + } + else { + sseq->zoom= 1.0f; + } + } + + + ED_area_tag_redraw(CTX_wm_area(C)); + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_view_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "View All"; + ot->idname= "SEQUENCER_OT_view_all"; + + /* api callbacks */ + ot->exec= sequencer_view_all_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER; +} + + +/* view_all operator */ +static int sequencer_view_selected_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + View2D *v2d= UI_view2d_fromcontext(C); + ScrArea *area= CTX_wm_area(C); + bScreen *sc= CTX_wm_screen(C); + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq; + + int xmin= MAXFRAME*2; + int xmax= -MAXFRAME*2; + int ymin= MAXSEQ+1; + int ymax= 0; + int orig_height; + int ymid; + int ymargin= 1; + int xmargin= FPS; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + for(seq=ed->seqbasep->first; seq; seq=seq->next) { + if(seq->flag & SELECT) { + xmin= MIN2(xmin, seq->startdisp); + xmax= MAX2(xmax, seq->enddisp); + + ymin= MIN2(ymin, seq->machine); + ymax= MAX2(ymax, seq->machine); + } + } + + if (ymax != 0) { + + xmax += xmargin; + xmin -= xmargin; + ymax += ymargin; + ymin -= ymargin; + + orig_height= v2d->cur.ymax - v2d->cur.ymin; + + v2d->cur.xmin= xmin; + v2d->cur.xmax= xmax; + + v2d->cur.ymin= ymin; + v2d->cur.ymax= ymax; + + /* only zoom out vertically */ + if (orig_height > v2d->cur.ymax - v2d->cur.ymin) { + ymid= (v2d->cur.ymax + v2d->cur.ymin) / 2; + + v2d->cur.ymin= ymid - (orig_height/2); + v2d->cur.ymax= ymid + (orig_height/2); + } + + UI_view2d_curRect_validate(v2d); + UI_view2d_sync(sc, area, v2d, V2D_LOCK_COPY); + + ED_area_tag_redraw(CTX_wm_area(C)); + } + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_view_selected(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "View Selected"; + ot->idname= "SEQUENCER_OT_view_selected"; + + /* api callbacks */ + ot->exec= sequencer_view_selected_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER; +} diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h new file mode 100644 index 00000000000..1f78c4d5199 --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -0,0 +1,154 @@ +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation, Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef ED_SEQUENCER_INTERN_H +#define ED_SEQUENCER_INTERN_H + +#include "RNA_access.h" +#include "DNA_sequence_types.h" + +/* internal exports only */ + +struct Sequence; +struct bContext; +struct rctf; +struct SpaceSeq; +struct ScrArea; +struct ARegion; +struct ARegionType; +struct Scene; + +/* space_sequencer.c */ +struct ARegion *sequencer_has_buttons_region(struct ScrArea *sa); + +/* sequencer_header.c */ +// void sequencer_header_buttons(const struct bContext *C, struct ARegion *ar); + +/* sequencer_draw.c */ +void drawseqspace(const struct bContext *C, struct ARegion *ar); +void seq_reset_imageofs(struct SpaceSeq *sseq); + +/* sequencer_edit.c */ +struct View2D; +int check_single_seq(struct Sequence *seq); +int seq_tx_get_final_left(struct Sequence *seq, int metaclip); +int seq_tx_get_final_right(struct Sequence *seq, int metaclip); +void seq_rectf(struct Sequence *seq, struct rctf *rectf); +void boundbox_seq(struct Scene *scene, struct rctf *rect); +struct Sequence *get_last_seq(struct Scene *scene); +struct Sequence *find_nearest_seq(struct Scene *scene, struct View2D *v2d, int *hand, short mval[2]); +struct Sequence *find_neighboring_sequence(struct Scene *scene, struct Sequence *test, int lr, int sel); +void deselect_all_seq(struct Scene *scene); +void recurs_sel_seq(struct Sequence *seqm); +int event_to_efftype(int event); +void set_last_seq(struct Scene *scene, struct Sequence *seq); +int seq_effect_find_selected(struct Scene *scene, struct Sequence *activeseq, int type, struct Sequence **selseq1, struct Sequence **selseq2, struct Sequence **selseq3, char **error_str); +struct Sequence *alloc_sequence(struct ListBase *lb, int cfra, int machine); + +/* externs */ +extern EnumPropertyItem sequencer_prop_effect_types[]; +extern EnumPropertyItem prop_side_types[]; + +/* operators */ +struct wmOperatorType; +struct wmWindowManager; +void SEQUENCER_OT_cut(struct wmOperatorType *ot); +void SEQUENCER_OT_mute(struct wmOperatorType *ot); +void SEQUENCER_OT_unmute(struct wmOperatorType *ot); +void SEQUENCER_OT_lock(struct wmOperatorType *ot); +void SEQUENCER_OT_unlock(struct wmOperatorType *ot); +void SEQUENCER_OT_reload(struct wmOperatorType *ot); +void SEQUENCER_OT_refresh_all(struct wmOperatorType *ot); +void SEQUENCER_OT_duplicate_add(struct wmOperatorType *ot); +void SEQUENCER_OT_delete(struct wmOperatorType *ot); +void SEQUENCER_OT_images_separate(struct wmOperatorType *ot); +void SEQUENCER_OT_meta_toggle(struct wmOperatorType *ot); +void SEQUENCER_OT_meta_make(struct wmOperatorType *ot); +void SEQUENCER_OT_meta_separate(struct wmOperatorType *ot); + +void SEQUENCER_OT_view_all(struct wmOperatorType *ot); +void SEQUENCER_OT_view_selected(struct wmOperatorType *ot); + +/* sequencer_select.c */ +void SEQUENCER_OT_select_all_toggle(struct wmOperatorType *ot); +void SEQUENCER_OT_select(struct wmOperatorType *ot); +void SEQUENCER_OT_select_more(struct wmOperatorType *ot); +void SEQUENCER_OT_select_less(struct wmOperatorType *ot); +void SEQUENCER_OT_select_linked(struct wmOperatorType *ot); +void SEQUENCER_OT_select_linked_pick(struct wmOperatorType *ot); +void SEQUENCER_OT_select_handles(struct wmOperatorType *ot); +void SEQUENCER_OT_select_active_side(struct wmOperatorType *ot); +void SEQUENCER_OT_select_border(struct wmOperatorType *ot); +void SEQUENCER_OT_select_invert(struct wmOperatorType *ot); + + +/* sequencer_select.c */ +void SEQUENCER_OT_scene_strip_add(struct wmOperatorType *ot); +void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot); +void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot); +void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot); +void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot); + +/* RNA enums, just to be more readable */ +enum { + SEQ_SIDE_NONE=0, + SEQ_SIDE_LEFT, + SEQ_SIDE_RIGHT, + SEQ_SIDE_BOTH, +}; +enum { + SEQ_CUT_SOFT, + SEQ_CUT_HARD, +}; +enum { + SEQ_SELECTED, + SEQ_UNSELECTED, +}; + +/* defines used internally */ +#define SEQ_ALLSEL (SELECT+SEQ_LEFTSEL+SEQ_RIGHTSEL) +#define SEQ_DESEL ~SEQ_ALLSEL +#define SCE_MARKERS 0 // XXX - dummy + +/* sequencer_ops.c */ +void sequencer_operatortypes(void); +void sequencer_keymap(struct wmWindowManager *wm); + +/* sequencer_scope.c */ +struct ImBuf *make_waveform_view_from_ibuf(struct ImBuf * ibuf); +struct ImBuf *make_sep_waveform_view_from_ibuf(struct ImBuf * ibuf); +struct ImBuf *make_vectorscope_view_from_ibuf(struct ImBuf * ibuf); +struct ImBuf *make_zebra_view_from_ibuf(struct ImBuf * ibuf, float perc); +struct ImBuf *make_histogram_view_from_ibuf(struct ImBuf * ibuf); + +/* sequencer_buttons.c */ + +void SEQUENCER_OT_properties(struct wmOperatorType *ot); +void sequencer_buttons_register(struct ARegionType *art); + +#endif /* ED_SEQUENCER_INTERN_H */ + diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c new file mode 100644 index 00000000000..600ef87e1b3 --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_ops.c @@ -0,0 +1,185 @@ + +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_userdef_types.h" +#include "DNA_windowmanager_types.h" + +#include "BLI_arithb.h" +#include "BLI_blenlib.h" + +#include "BIF_transform.h" /* transform keymap */ + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_utildefines.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_screen.h" + +#include "sequencer_intern.h" + + +/* ************************** registration **********************************/ + + +void sequencer_operatortypes(void) +{ + /* sequencer_edit.c */ + WM_operatortype_append(SEQUENCER_OT_cut); + WM_operatortype_append(SEQUENCER_OT_mute); + WM_operatortype_append(SEQUENCER_OT_unmute); + WM_operatortype_append(SEQUENCER_OT_lock); + WM_operatortype_append(SEQUENCER_OT_unlock); + WM_operatortype_append(SEQUENCER_OT_reload); + WM_operatortype_append(SEQUENCER_OT_refresh_all); + WM_operatortype_append(SEQUENCER_OT_duplicate_add); + WM_operatortype_append(SEQUENCER_OT_delete); + WM_operatortype_append(SEQUENCER_OT_images_separate); + WM_operatortype_append(SEQUENCER_OT_meta_toggle); + WM_operatortype_append(SEQUENCER_OT_meta_make); + WM_operatortype_append(SEQUENCER_OT_meta_separate); + + WM_operatortype_append(SEQUENCER_OT_view_all); + WM_operatortype_append(SEQUENCER_OT_view_selected); + + /* sequencer_select.c */ + WM_operatortype_append(SEQUENCER_OT_select_all_toggle); + WM_operatortype_append(SEQUENCER_OT_select_invert); + WM_operatortype_append(SEQUENCER_OT_select); + WM_operatortype_append(SEQUENCER_OT_select_more); + WM_operatortype_append(SEQUENCER_OT_select_less); + WM_operatortype_append(SEQUENCER_OT_select_linked_pick); + WM_operatortype_append(SEQUENCER_OT_select_linked); + WM_operatortype_append(SEQUENCER_OT_select_handles); + WM_operatortype_append(SEQUENCER_OT_select_active_side); + WM_operatortype_append(SEQUENCER_OT_select_border); + + /* sequencer_add.c */ + WM_operatortype_append(SEQUENCER_OT_scene_strip_add); + WM_operatortype_append(SEQUENCER_OT_movie_strip_add); + WM_operatortype_append(SEQUENCER_OT_sound_strip_add); + WM_operatortype_append(SEQUENCER_OT_image_strip_add); + WM_operatortype_append(SEQUENCER_OT_effect_strip_add); + WM_operatortype_append(SEQUENCER_OT_properties); +} + + +void sequencer_keymap(wmWindowManager *wm) +{ + ListBase *keymap= WM_keymap_listbase(wm, "Sequencer", SPACE_SEQ, 0); + wmKeymapItem *kmi; + + WM_keymap_add_item(keymap, "SEQUENCER_OT_properties", NKEY, KM_PRESS, 0, 0); + + WM_keymap_add_item(keymap, "SEQUENCER_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "SEQUENCER_OT_select_invert", IKEY, KM_PRESS, KM_CTRL, 0); + + RNA_enum_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_cut", KKEY, KM_PRESS, 0, 0)->ptr, "type", SEQ_CUT_SOFT); + RNA_enum_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_cut", KKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", SEQ_CUT_HARD); + + RNA_enum_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_mute", HKEY, KM_PRESS, 0, 0)->ptr, "type", SEQ_SELECTED); + RNA_enum_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_mute", HKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "type", SEQ_UNSELECTED); + + RNA_enum_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_unmute", HKEY, KM_PRESS, KM_ALT, 0)->ptr, "type", SEQ_SELECTED); + RNA_enum_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_unmute", HKEY, KM_PRESS, KM_ALT|KM_SHIFT, 0)->ptr, "type", SEQ_UNSELECTED); + + WM_keymap_add_item(keymap, "SEQUENCER_OT_lock", LKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "SEQUENCER_OT_unlock", HKEY, KM_PRESS, KM_SHIFT|KM_ALT, 0); + + WM_keymap_add_item(keymap, "SEQUENCER_OT_reload", RKEY, KM_PRESS, KM_ALT, 0); + + WM_keymap_add_item(keymap, "SEQUENCER_OT_duplicate_add", DKEY, KM_PRESS, KM_SHIFT, 0); + + WM_keymap_add_item(keymap, "SEQUENCER_OT_delete", XKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "SEQUENCER_OT_delete", DELKEY, KM_PRESS, 0, 0); + + WM_keymap_add_item(keymap, "SEQUENCER_OT_images_separate", YKEY, KM_PRESS, 0, 0); + + WM_keymap_add_item(keymap, "SEQUENCER_OT_meta_toggle", TABKEY, KM_PRESS, 0, 0); + + WM_keymap_add_item(keymap, "SEQUENCER_OT_meta_make", MKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "SEQUENCER_OT_meta_separate", MKEY, KM_PRESS, KM_ALT, 0); + + WM_keymap_add_item(keymap, "SEQUENCER_OT_view_all", HOMEKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "SEQUENCER_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0); + + + /* Mouse selection, a bit verbose :/ */ + WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0); + RNA_boolean_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1); + RNA_boolean_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "linked_left", 1); + RNA_boolean_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "linked_right", 1); + + kmi= WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL|KM_ALT, 0); + RNA_boolean_set(kmi->ptr, "linked_left", 1); + RNA_boolean_set(kmi->ptr, "linked_right", 1); + + kmi= WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_CTRL|KM_ALT, 0); + RNA_boolean_set(kmi->ptr, "extend", 1); + RNA_boolean_set(kmi->ptr, "linked_left", 1); + RNA_boolean_set(kmi->ptr, "linked_right", 1); + + kmi= WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "extend", 1); + RNA_boolean_set(kmi->ptr, "linked_left", 1); + + kmi= WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_ALT, 0); + RNA_boolean_set(kmi->ptr, "extend", 1); + RNA_boolean_set(kmi->ptr, "linked_right", 1); + + + + WM_keymap_add_item(keymap, "SEQUENCER_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "SEQUENCER_OT_select_less", PADMINUS, KM_PRESS, KM_CTRL, 0); + + WM_keymap_add_item(keymap, "SEQUENCER_OT_select_linked_pick", LKEY, KM_PRESS, 0, 0); + RNA_boolean_set(WM_keymap_add_item(keymap, "SEQUENCER_OT_select_linked_pick", LKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1); + + WM_keymap_add_item(keymap, "SEQUENCER_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0); + + WM_keymap_add_item(keymap, "SEQUENCER_OT_select_border", BKEY, KM_PRESS, 0, 0); + + WM_keymap_verify_item(keymap, "ANIM_OT_change_frame", LEFTMOUSE, KM_PRESS, 0, 0); + + transform_keymap_for_space(wm, keymap, SPACE_SEQ); +} + diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c new file mode 100644 index 00000000000..e26f445ae44 --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_scopes.c @@ -0,0 +1,701 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Author: Peter Schlaile < peter [at] schlaile [dot] de > + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#include <math.h> +#include <string.h> + +#include "BKE_utildefines.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "sequencer_intern.h" + +static void rgb_to_yuv(float rgb[3], float yuv[3]) +{ + yuv[0]= 0.299*rgb[0] + 0.587*rgb[1] + 0.114*rgb[2]; + yuv[1]= 0.492*(rgb[2] - yuv[0]); + yuv[2]= 0.877*(rgb[0] - yuv[0]); + + /* Normalize */ + yuv[1]*= 255.0/(122*2.0); + yuv[1]+= 0.5; + + yuv[2]*= 255.0/(157*2.0); + yuv[2]+= 0.5; +} + +static void scope_put_pixel(unsigned char* table, unsigned char * pos) +{ + char newval = table[*pos]; + pos[0] = pos[1] = pos[2] = newval; + pos[3] = 255; +} + +static void scope_put_pixel_single(unsigned char* table, unsigned char * pos, + int col) +{ + char newval = table[pos[col]]; + pos[col] = newval; + pos[3] = 255; +} + +static void wform_put_line(int w, + unsigned char * last_pos, unsigned char * new_pos) +{ + if (last_pos > new_pos) { + unsigned char* temp = new_pos; + new_pos = last_pos; + last_pos = temp; + } + + while (last_pos < new_pos) { + if (last_pos[0] == 0) { + last_pos[0] = last_pos[1] = last_pos[2] = 32; + last_pos[3] = 255; + } + last_pos += 4*w; + } +} + +static void wform_put_line_single( + int w, unsigned char * last_pos, unsigned char * new_pos, int col) +{ + if (last_pos > new_pos) { + unsigned char* temp = new_pos; + new_pos = last_pos; + last_pos = temp; + } + + while (last_pos < new_pos) { + if (last_pos[col] == 0) { + last_pos[col] = 32; + last_pos[3] = 255; + } + last_pos += 4*w; + } +} + +static void wform_put_border(unsigned char * tgt, int w, int h) +{ + int x, y; + + for (x = 0; x < w; x++) { + unsigned char * p = tgt + 4 * x; + p[1] = p[3] = 255.0; + p[4 * w + 1] = p[4 * w + 3] = 255.0; + p = tgt + 4 * (w * (h - 1) + x); + p[1] = p[3] = 255.0; + p[-4 * w + 1] = p[-4 * w + 3] = 255.0; + } + + for (y = 0; y < h; y++) { + unsigned char * p = tgt + 4 * w * y; + p[1] = p[3] = 255.0; + p[4 + 1] = p[4 + 3] = 255.0; + p = tgt + 4 * (w * y + w - 1); + p[1] = p[3] = 255.0; + p[-4 + 1] = p[-4 + 3] = 255.0; + } +} + +static void wform_put_gridrow(unsigned char * tgt, float perc, int w, int h) +{ + int i; + + tgt += (int) (perc/100.0 * h) * w * 4; + + for (i = 0; i < w*2; i++) { + tgt[0] = 255; + + tgt += 4; + } +} + +static void wform_put_grid(unsigned char * tgt, int w, int h) +{ + wform_put_gridrow(tgt, 90.0, w, h); + wform_put_gridrow(tgt, 70.0, w, h); + wform_put_gridrow(tgt, 10.0, w, h); +} + +static struct ImBuf *make_waveform_view_from_ibuf_byte(struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect, 0); + int x,y; + unsigned char* src = (unsigned char*) ibuf->rect; + unsigned char* tgt = (unsigned char*) rval->rect; + int w = ibuf->x + 3; + int h = 515; + float waveform_gamma = 0.2; + unsigned char wtable[256]; + + wform_put_grid(tgt, w, h); + + for (x = 0; x < 256; x++) { + wtable[x] = (unsigned char) (pow(((float) x + 1)/256, + waveform_gamma)*255); + } + + for (y = 0; y < ibuf->y; y++) { + unsigned char * last_p = 0; + + for (x = 0; x < ibuf->x; x++) { + unsigned char * rgb = src + 4 * (ibuf->x * y + x); + float v = 1.0 * + ( 0.299*rgb[0] + + 0.587*rgb[1] + + 0.114*rgb[2]) / 255.0; + unsigned char * p = tgt; + p += 4 * (w * ((int) (v * (h - 3)) + 1) + x + 1); + + scope_put_pixel(wtable, p); + p += 4 * w; + scope_put_pixel(wtable, p); + + if (last_p != 0) { + wform_put_line(w, last_p, p); + } + last_p = p; + } + } + + wform_put_border(tgt, w, h); + + return rval; +} + +static struct ImBuf *make_waveform_view_from_ibuf_float(struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect, 0); + int x,y; + float* src = ibuf->rect_float; + unsigned char* tgt = (unsigned char*) rval->rect; + int w = ibuf->x + 3; + int h = 515; + float waveform_gamma = 0.2; + unsigned char wtable[256]; + + wform_put_grid(tgt, w, h); + + for (x = 0; x < 256; x++) { + wtable[x] = (unsigned char) (pow(((float) x + 1)/256, + waveform_gamma)*255); + } + + for (y = 0; y < ibuf->y; y++) { + unsigned char * last_p = 0; + + for (x = 0; x < ibuf->x; x++) { + float * rgb = src + 4 * (ibuf->x * y + x); + float v = 1.0 * + ( 0.299*rgb[0] + + 0.587*rgb[1] + + 0.114*rgb[2]); + unsigned char * p = tgt; + + CLAMP(v, 0.0, 1.0); + + p += 4 * (w * ((int) (v * (h - 3)) + 1) + x + 1); + + scope_put_pixel(wtable, p); + p += 4 * w; + scope_put_pixel(wtable, p); + + if (last_p != 0) { + wform_put_line(w, last_p, p); + } + last_p = p; + } + } + + wform_put_border(tgt, w, h); + + return rval; +} + +struct ImBuf *make_waveform_view_from_ibuf(struct ImBuf * ibuf) +{ + if (ibuf->rect_float) { + return make_waveform_view_from_ibuf_float(ibuf); + } else { + return make_waveform_view_from_ibuf_byte(ibuf); + } +} + + +static struct ImBuf *make_sep_waveform_view_from_ibuf_byte(struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf( + ibuf->x + 3, 515, 32, IB_rect, 0); + int x,y; + unsigned char* src = (unsigned char*) ibuf->rect; + unsigned char* tgt = (unsigned char*) rval->rect; + int w = ibuf->x + 3; + int sw = ibuf->x/3; + int h = 515; + float waveform_gamma = 0.2; + unsigned char wtable[256]; + + wform_put_grid(tgt, w, h); + + for (x = 0; x < 256; x++) { + wtable[x] = (unsigned char) (pow(((float) x + 1)/256, + waveform_gamma)*255); + } + + for (y = 0; y < ibuf->y; y++) { + unsigned char * last_p[3] = {0,0,0}; + + for (x = 0; x < ibuf->x; x++) { + int c; + unsigned char * rgb = src + 4 * (ibuf->x * y + x); + for (c = 0; c < 3; c++) { + unsigned char * p = tgt; + p += 4 * (w * ((rgb[c] * (h - 3))/255 + 1) + + c * sw + x/3 + 1); + + scope_put_pixel_single(wtable, p, c); + p += 4 * w; + scope_put_pixel_single(wtable, p, c); + + if (last_p[c] != 0) { + wform_put_line_single( + w, last_p[c], p, c); + } + last_p[c] = p; + } + } + } + + wform_put_border(tgt, w, h); + + return rval; +} + +static struct ImBuf *make_sep_waveform_view_from_ibuf_float( + struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf( + ibuf->x + 3, 515, 32, IB_rect, 0); + int x,y; + float* src = ibuf->rect_float; + unsigned char* tgt = (unsigned char*) rval->rect; + int w = ibuf->x + 3; + int sw = ibuf->x/3; + int h = 515; + float waveform_gamma = 0.2; + unsigned char wtable[256]; + + wform_put_grid(tgt, w, h); + + for (x = 0; x < 256; x++) { + wtable[x] = (unsigned char) (pow(((float) x + 1)/256, + waveform_gamma)*255); + } + + for (y = 0; y < ibuf->y; y++) { + unsigned char * last_p[3] = {0, 0, 0}; + + for (x = 0; x < ibuf->x; x++) { + int c; + float * rgb = src + 4 * (ibuf->x * y + x); + for (c = 0; c < 3; c++) { + unsigned char * p = tgt; + float v = rgb[c]; + + CLAMP(v, 0.0, 1.0); + + p += 4 * (w * ((int) (v * (h - 3)) + 1) + + c * sw + x/3 + 1); + + scope_put_pixel_single(wtable, p, c); + p += 4 * w; + scope_put_pixel_single(wtable, p, c); + + if (last_p[c] != 0) { + wform_put_line_single( + w, last_p[c], p, c); + } + last_p[c] = p; + } + } + } + + wform_put_border(tgt, w, h); + + return rval; +} + +struct ImBuf *make_sep_waveform_view_from_ibuf(struct ImBuf * ibuf) +{ + if (ibuf->rect_float) { + return make_sep_waveform_view_from_ibuf_float(ibuf); + } else { + return make_sep_waveform_view_from_ibuf_byte(ibuf); + } +} + +static void draw_zebra_byte(struct ImBuf * src,struct ImBuf * ibuf, float perc) +{ + unsigned int limit = 255 * perc / 100.0; + unsigned char * p = (unsigned char*) src->rect; + unsigned char * o = (unsigned char*) ibuf->rect; + int x; + int y; + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + unsigned char r = *p++; + unsigned char g = *p++; + unsigned char b = *p++; + unsigned char a = *p++; + + if (r >= limit || g >= limit || b >= limit) { + if (((x + y) & 0x08) != 0) { + r = 255 - r; + g = 255 - g; + b = 255 - b; + } + } + *o++ = r; + *o++ = g; + *o++ = b; + *o++ = a; + } + } +} + + +static void draw_zebra_float(struct ImBuf * src,struct ImBuf * ibuf,float perc) +{ + float limit = perc / 100.0; + float * p = src->rect_float; + unsigned char * o = (unsigned char*) ibuf->rect; + int x; + int y; + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + float r = *p++; + float g = *p++; + float b = *p++; + float a = *p++; + + if (r >= limit || g >= limit || b >= limit) { + if (((x + y) & 0x08) != 0) { + r = -r; + g = -g; + b = -b; + } + } + + *o++ = FTOCHAR(r); + *o++ = FTOCHAR(g); + *o++ = FTOCHAR(b); + *o++ = FTOCHAR(a); + } + } +} + +struct ImBuf * make_zebra_view_from_ibuf(struct ImBuf * src, float perc) +{ + struct ImBuf * ibuf = IMB_allocImBuf(src->x, src->y, 32, IB_rect, 0); + + if (src->rect_float) { + draw_zebra_float(src, ibuf, perc); + } else { + draw_zebra_byte(src, ibuf, perc); + } + return ibuf; +} + +static void draw_histogram_marker(struct ImBuf * ibuf, int x) +{ + unsigned char * p = (unsigned char*) ibuf->rect; + int barh = ibuf->y * 0.1; + int i; + + p += 4 * (x + ibuf->x * (ibuf->y - barh + 1)); + + for (i = 0; i < barh-1; i++) { + p[0] = p[1] = p[2] = 255; + p += ibuf->x * 4; + } +} + +static void draw_histogram_bar(struct ImBuf * ibuf, int x,float val, int col) +{ + unsigned char * p = (unsigned char*) ibuf->rect; + int barh = ibuf->y * val * 0.9; + int i; + + p += 4 * (x + ibuf->x); + + for (i = 0; i < barh; i++) { + p[col] = 255; + p += ibuf->x * 4; + } +} + +static struct ImBuf *make_histogram_view_from_ibuf_byte( + struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf(515, 128, 32, IB_rect, 0); + int n,c,x,y; + unsigned char* src = (unsigned char*) ibuf->rect; + + unsigned int bins[3][256]; + + memset(bins, 0, 3 * 256* sizeof(unsigned int)); + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + bins[0][*src++]++; + bins[1][*src++]++; + bins[2][*src++]++; + src++; + } + } + + n = 0; + for (c = 0; c < 3; c++) { + for (x = 0; x < 256; x++) { + if (bins[c][x] > n) { + n = bins[c][x]; + } + } + } + + for (c = 0; c < 3; c++) { + for (x = 0; x < 256; x++) { + draw_histogram_bar(rval, x*2+1, + ((float) bins[c][x])/n, c); + draw_histogram_bar(rval, x*2+2, + ((float) bins[c][x])/n, c); + } + } + + wform_put_border((unsigned char*) rval->rect, rval->x, rval->y); + + return rval; +} + +static int get_bin_float(float f) +{ + if (f < -0.25) { + f = -0.25; + } else if (f > 1.25) { + f = 1.25; + } + + return (int) (((f + 0.25) / 1.5) * 512); +} + +static struct ImBuf *make_histogram_view_from_ibuf_float( + struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf(515, 128, 32, IB_rect, 0); + int n,c,x,y; + float* src = ibuf->rect_float; + + unsigned int bins[3][512]; + + memset(bins, 0, 3 * 256* sizeof(unsigned int)); + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + bins[0][get_bin_float(*src++)]++; + bins[1][get_bin_float(*src++)]++; + bins[2][get_bin_float(*src++)]++; + src++; + } + } + + draw_histogram_marker(rval, get_bin_float(0.0)); + draw_histogram_marker(rval, get_bin_float(1.0)); + + n = 0; + for (c = 0; c < 3; c++) { + for (x = 0; x < 512; x++) { + if (bins[c][x] > n) { + n = bins[c][x]; + } + } + } + for (c = 0; c < 3; c++) { + for (x = 0; x < 512; x++) { + draw_histogram_bar(rval, x+1, (float) bins[c][x]/n, c); + } + } + + wform_put_border((unsigned char*) rval->rect, rval->x, rval->y); + + return rval; +} + +struct ImBuf *make_histogram_view_from_ibuf(struct ImBuf * ibuf) +{ + if (ibuf->rect_float) { + return make_histogram_view_from_ibuf_float(ibuf); + } else { + return make_histogram_view_from_ibuf_byte(ibuf); + } +} + +static void vectorscope_put_cross(unsigned char r, unsigned char g, + unsigned char b, + char * tgt, int w, int h, int size) +{ + float rgb[3], yuv[3]; + char * p; + int x = 0; + int y = 0; + + rgb[0]= (float)r/255.0; + rgb[1]= (float)g/255.0; + rgb[2]= (float)b/255.0; + rgb_to_yuv(rgb, yuv); + + p = tgt + 4 * (w * (int) ((yuv[2] * (h - 3) + 1)) + + (int) ((yuv[1] * (w - 3) + 1))); + + if (r == 0 && g == 0 && b == 0) { + r = 255; + } + + for (y = -size; y <= size; y++) { + for (x = -size; x <= size; x++) { + char * q = p + 4 * (y * w + x); + q[0] = r; q[1] = g; q[2] = b; q[3] = 255; + } + } +} + +static struct ImBuf *make_vectorscope_view_from_ibuf_byte(struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf(515, 515, 32, IB_rect, 0); + int x,y; + char* src = (char*) ibuf->rect; + char* tgt = (char*) rval->rect; + float rgb[3], yuv[3]; + int w = 515; + int h = 515; + float scope_gamma = 0.2; + unsigned char wtable[256]; + + for (x = 0; x < 256; x++) { + wtable[x] = (unsigned char) (pow(((float) x + 1)/256, + scope_gamma)*255); + } + + for (x = 0; x <= 255; x++) { + vectorscope_put_cross(255 , 0,255 - x, tgt, w, h, 1); + vectorscope_put_cross(255 , x, 0, tgt, w, h, 1); + vectorscope_put_cross(255- x, 255, 0, tgt, w, h, 1); + vectorscope_put_cross(0, 255, x, tgt, w, h, 1); + vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1); + vectorscope_put_cross(x, 0, 255, tgt, w, h, 1); + } + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + char * src1 = src + 4 * (ibuf->x * y + x); + char * p; + + rgb[0]= (float)src1[0]/255.0; + rgb[1]= (float)src1[1]/255.0; + rgb[2]= (float)src1[2]/255.0; + rgb_to_yuv(rgb, yuv); + + p = tgt + 4 * (w * (int) ((yuv[2] * (h - 3) + 1)) + + (int) ((yuv[1] * (w - 3) + 1))); + scope_put_pixel(wtable, (unsigned char*)p); + } + } + + vectorscope_put_cross(0, 0, 0, tgt, w, h, 3); + + return rval; +} + +static struct ImBuf *make_vectorscope_view_from_ibuf_float(struct ImBuf * ibuf) +{ + struct ImBuf * rval = IMB_allocImBuf(515, 515, 32, IB_rect, 0); + int x,y; + float* src = ibuf->rect_float; + char* tgt = (char*) rval->rect; + float rgb[3], yuv[3]; + int w = 515; + int h = 515; + float scope_gamma = 0.2; + unsigned char wtable[256]; + + for (x = 0; x < 256; x++) { + wtable[x] = (unsigned char) (pow(((float) x + 1)/256, + scope_gamma)*255); + } + + for (x = 0; x <= 255; x++) { + vectorscope_put_cross(255 , 0,255 - x, tgt, w, h, 1); + vectorscope_put_cross(255 , x, 0, tgt, w, h, 1); + vectorscope_put_cross(255- x, 255, 0, tgt, w, h, 1); + vectorscope_put_cross(0, 255, x, tgt, w, h, 1); + vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1); + vectorscope_put_cross(x, 0, 255, tgt, w, h, 1); + } + + for (y = 0; y < ibuf->y; y++) { + for (x = 0; x < ibuf->x; x++) { + float * src1 = src + 4 * (ibuf->x * y + x); + char * p; + + memcpy(rgb, src1, 3 * sizeof(float)); + + CLAMP(rgb[0], 0.0, 1.0); + CLAMP(rgb[1], 0.0, 1.0); + CLAMP(rgb[2], 0.0, 1.0); + + rgb_to_yuv(rgb, yuv); + + p = tgt + 4 * (w * (int) ((yuv[2] * (h - 3) + 1)) + + (int) ((yuv[1] * (w - 3) + 1))); + scope_put_pixel(wtable, (unsigned char*)p); + } + } + + vectorscope_put_cross(0, 0, 0, tgt, w, h, 3); + + return rval; +} + +struct ImBuf *make_vectorscope_view_from_ibuf(struct ImBuf * ibuf) +{ + if (ibuf->rect_float) { + return make_vectorscope_view_from_ibuf_float(ibuf); + } else { + return make_vectorscope_view_from_ibuf_byte(ibuf); + } +} diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c new file mode 100644 index 00000000000..bfd89ccdffb --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -0,0 +1,819 @@ +/** + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Blender Foundation, 2003-2009, Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <math.h> +#include <string.h> + +#ifndef WIN32 +#include <unistd.h> +#else +#include <io.h> +#endif +#include <sys/types.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "DNA_curve_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_sequence_types.h" +#include "DNA_view2d_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_sequence.h" +#include "BKE_scene.h" +#include "BKE_utildefines.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +/* for menu/popup icons etc etc*/ +#include "UI_interface.h" +#include "UI_resources.h" + +#include "ED_anim_api.h" +#include "ED_space_api.h" +#include "ED_types.h" +#include "ED_screen.h" +#include "ED_util.h" + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +/* own include */ +#include "sequencer_intern.h" +static void *find_nearest_marker() {return NULL;} +static void deselect_markers() {} + +void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRING BACK */ +{ + Sequence *neighbor; + + neighbor=find_neighboring_sequence(scene, test, SEQ_SIDE_LEFT, -1); + if (neighbor) { + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_RIGHTSEL; + } + neighbor=find_neighboring_sequence(scene, test, SEQ_SIDE_RIGHT, -1); + if (neighbor) { + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_LEFTSEL; + } + test->flag |= SELECT; +} + +/* used for mouse selection and for SEQUENCER_OT_select_active_side() */ +static void select_active_side(ListBase *seqbase, int sel_side, int channel, int frame) +{ + Sequence *seq; + + for(seq= seqbase->first; seq; seq=seq->next) { + if(channel==seq->machine) { + switch(sel_side) { + case SEQ_SIDE_LEFT: + if (frame > (seq->startdisp)) { + seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL); + seq->flag |= SELECT; + } + break; + case SEQ_SIDE_RIGHT: + if (frame < (seq->startdisp)) { + seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL); + seq->flag |= SELECT; + } + break; + case SEQ_SIDE_BOTH: + seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL); + break; + } + } + } +} + +#if 0 // BRING BACK +void select_surround_from_last(Scene *scene) +{ + Sequence *seq=get_last_seq(scene); + + if (seq==NULL) + return; + + select_surrounding_handles(scene, seq); +} +#endif + + +void select_single_seq(Scene *scene, Sequence *seq, int deselect_all) /* BRING BACK */ +{ + Editing *ed= seq_give_editing(scene, FALSE); + + if(deselect_all) + deselect_all_seq(scene); + set_last_seq(scene, seq); + + if((seq->type==SEQ_IMAGE) || (seq->type==SEQ_MOVIE)) { + if(seq->strip) + strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR-1); + } + else if((seq->type==SEQ_HD_SOUND) || (seq->type==SEQ_RAM_SOUND)) { + if(seq->strip) + strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR-1); + } + seq->flag|= SELECT; + recurs_sel_seq(seq); +} + +// remove this function, replace with invert operator +//void swap_select_seq(Scene *scene) + +void select_neighbor_from_last(Scene *scene, int lr) +{ + Sequence *seq=get_last_seq(scene); + Sequence *neighbor; + int change = 0; + if (seq) { + neighbor=find_neighboring_sequence(scene, seq, lr, -1); + if (neighbor) { + switch (lr) { + case SEQ_SIDE_LEFT: + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_RIGHTSEL; + seq->flag |= SEQ_LEFTSEL; + break; + case SEQ_SIDE_RIGHT: + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_LEFTSEL; + seq->flag |= SEQ_RIGHTSEL; + break; + } + seq->flag |= SELECT; + change = 1; + } + } + if (change) { + } +} + + +/* (de)select operator */ +static int sequencer_deselect_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq; + int desel = 0; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + for(seq= ed->seqbasep->first; seq; seq=seq->next) { + if(seq->flag & SEQ_ALLSEL) { + desel= 1; + break; + } + } + + for(seq= ed->seqbasep->first; seq; seq=seq->next) { + if (desel) { + seq->flag &= SEQ_DESEL; + } + else { + seq->flag &= (SEQ_LEFTSEL+SEQ_RIGHTSEL); + seq->flag |= SELECT; + } + } + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_select_all_toggle(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "(De)Select All"; + ot->idname= "SEQUENCER_OT_select_all_toggle"; + + /* api callbacks */ + ot->exec= sequencer_deselect_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + + +/* (de)select operator */ +static int sequencer_select_invert_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + for(seq= ed->seqbasep->first; seq; seq=seq->next) { + if (seq->flag & SELECT) { + seq->flag &= SEQ_DESEL; + } + else { + seq->flag &= (SEQ_LEFTSEL+SEQ_RIGHTSEL); + seq->flag |= SELECT; + } + } + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_select_invert(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Invert"; + ot->idname= "SEQUENCER_OT_select_invert"; + + /* api callbacks */ + ot->exec= sequencer_select_invert_exec; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +static int sequencer_select_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + ARegion *ar= CTX_wm_region(C); + View2D *v2d= UI_view2d_fromcontext(C); + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + short extend= RNA_boolean_get(op->ptr, "extend"); + short linked_left= RNA_boolean_get(op->ptr, "linked_left"); + short linked_right= RNA_boolean_get(op->ptr, "linked_right"); + + short mval[2]; + + Sequence *seq,*neighbor; + int hand,sel_side, shift= 0; // XXX + TimeMarker *marker; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + marker=find_nearest_marker(SCE_MARKERS, 1); //XXX - dummy function for now + + mval[0]= event->x - ar->winrct.xmin; + mval[1]= event->y - ar->winrct.ymin; + + if (marker) { + int oldflag; + /* select timeline marker */ + if (shift) { + oldflag= marker->flag; + if (oldflag & SELECT) + marker->flag &= ~SELECT; + else + marker->flag |= SELECT; + } + else { + deselect_markers(0, 0); + marker->flag |= SELECT; + } + + } else { + + seq= find_nearest_seq(scene, v2d, &hand, mval); + + if(extend == 0 && linked_left==0 && linked_right==0) + deselect_all_seq(scene); + + if(seq) { + set_last_seq(scene, seq); + + if ((seq->type == SEQ_IMAGE) || (seq->type == SEQ_MOVIE)) { + if(seq->strip) { + strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR-1); + } + } else + if (seq->type == SEQ_HD_SOUND || seq->type == SEQ_RAM_SOUND) { + if(seq->strip) { + strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR-1); + } + } + + if(extend && (seq->flag & SELECT)) { + switch(hand) { + case SEQ_SIDE_NONE: + if (linked_left==0 && linked_right==0) + seq->flag &= SEQ_DESEL; + break; + case SEQ_SIDE_LEFT: + seq->flag ^= SEQ_LEFTSEL; + break; + case SEQ_SIDE_RIGHT: + seq->flag ^= SEQ_RIGHTSEL; + break; + } + } + else { + seq->flag |= SELECT; + if(hand==SEQ_SIDE_LEFT) seq->flag |= SEQ_LEFTSEL; + if(hand==SEQ_SIDE_RIGHT) seq->flag |= SEQ_RIGHTSEL; + } + + /* On Ctrl-Alt selection, select the strip and bordering handles */ + if (linked_left && linked_right) { + if(extend==0) deselect_all_seq(scene); + seq->flag |= SELECT; + select_surrounding_handles(scene, seq); + } + else if ((linked_left || linked_right) && (seq->flag & SELECT)) { + /* + * First click selects adjacent handles on that side. + * Second click selects all strips in that direction. + * If there are no adjacent strips, it just selects all in that direction. + */ + sel_side= linked_left ? SEQ_SIDE_LEFT:SEQ_SIDE_RIGHT; + neighbor=find_neighboring_sequence(scene, seq, sel_side, -1); + if (neighbor) { + switch (sel_side) { + case SEQ_SIDE_LEFT: + if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) { + if(extend==0) deselect_all_seq(scene); + seq->flag |= SELECT; + + select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp); + } else { + if(extend==0) deselect_all_seq(scene); + seq->flag |= SELECT; + + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_RIGHTSEL; + seq->flag |= SEQ_LEFTSEL; + } + break; + case SEQ_SIDE_RIGHT: + if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) { + if(extend==0) deselect_all_seq(scene); + seq->flag |= SELECT; + + select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp); + } else { + if(extend==0) deselect_all_seq(scene); + seq->flag |= SELECT; + + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_LEFTSEL; + seq->flag |= SEQ_RIGHTSEL; + } + break; + } + } else { + if(extend==0) deselect_all_seq(scene); + select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp); + } + } + recurs_sel_seq(seq); + } + } + + /* marker transform */ +#if 0 // XXX probably need to redo this differently for 2.5 + if (marker) { + short mval[2], xo, yo; +// getmouseco_areawin(mval); + xo= mval[0]; + yo= mval[1]; + + while(get_mbut()) { +// getmouseco_areawin(mval); + if(abs(mval[0]-xo)+abs(mval[1]-yo) > 4) { + transform_markers('g', 0); + return; + } + } + } +#endif + + ED_area_tag_redraw(CTX_wm_area(C)); + /* allowing tweaks */ + return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH; +} + +void SEQUENCER_OT_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Activate/Select"; + ot->idname= "SEQUENCER_OT_select"; + + /* api callbacks */ + ot->invoke= sequencer_select_invoke; + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "extend", 0, "Extend", "extend the selection"); + RNA_def_boolean(ot->srna, "linked_left", 0, "Linked Left", "Select strips to the left of the active strip"); + RNA_def_boolean(ot->srna, "linked_right", 0, "Linked Right", "Select strips to the right of the active strip"); +} + + + + +/* run recursivly to select linked */ +static int select_more_less_seq__internal(Scene *scene, int sel, int linked) { + Editing *ed= seq_give_editing(scene, FALSE); + Sequence *seq, *neighbor; + int change=0; + int isel; + + if(ed==NULL) return 0; + + if (sel) { + sel = SELECT; + isel = 0; + } else { + sel = 0; + isel = SELECT; + } + + if (!linked) { + /* if not linked we only want to touch each seq once, newseq */ + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + seq->tmp = NULL; + } + } + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + if((int)(seq->flag & SELECT) == sel) { + if ((linked==0 && seq->tmp)==0) { + /* only get unselected nabours */ + neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, isel); + if (neighbor) { + if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);} + else neighbor->flag &= ~SELECT; + if (linked==0) neighbor->tmp = (Sequence *)1; + change = 1; + } + neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, isel); + if (neighbor) { + if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);} + else neighbor->flag &= ~SELECT; + if (linked==0) neighbor->tmp = (void *)1; + change = 1; + } + } + } + } + + return change; +} + + + +/* select more operator */ +static int sequencer_select_more_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + + if (select_more_less_seq__internal(scene, 0, 0)) { + ED_area_tag_redraw(CTX_wm_area(C)); + } + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_select_more(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select More"; + ot->idname= "SEQUENCER_OT_select_more"; + + /* api callbacks */ + ot->exec= sequencer_select_more_exec; + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ +} + + +/* select less operator */ +static int sequencer_select_less_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + + if (select_more_less_seq__internal(scene, 1, 0)) { + ED_area_tag_redraw(CTX_wm_area(C)); + } + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_select_less(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select less"; + ot->idname= "SEQUENCER_OT_select_less"; + + /* api callbacks */ + ot->exec= sequencer_select_less_exec; + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ +} + + +/* select pick linked operator (uses the mouse) */ +static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + Scene *scene= CTX_data_scene(C); + ARegion *ar= CTX_wm_region(C); + View2D *v2d= UI_view2d_fromcontext(C); + + short extend= RNA_boolean_get(op->ptr, "extend"); + short mval[2]; + + Sequence *mouse_seq; + int selected, hand; + + mval[0]= event->x - ar->winrct.xmin; + mval[1]= event->y - ar->winrct.ymin; + + /* this works like UV, not mesh */ + mouse_seq= find_nearest_seq(scene, v2d, &hand, mval); + if (!mouse_seq) + return OPERATOR_FINISHED; /* user error as with mesh?? */ + + if (extend==0) + deselect_all_seq(scene); + + mouse_seq->flag |= SELECT; + recurs_sel_seq(mouse_seq); + + selected = 1; + while (selected) { + selected = select_more_less_seq__internal(scene, 1, 1); + } + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_select_linked_pick(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select pick linked"; + ot->idname= "SEQUENCER_OT_select_linked_pick"; + + /* api callbacks */ + ot->invoke= sequencer_select_linked_pick_invoke; + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "extend", 0, "Extend", "extend the selection"); +} + + +/* select linked operator */ +static int sequencer_select_linked_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + int selected; + + selected = 1; + while (selected) { + selected = select_more_less_seq__internal(scene, 1, 1); + } + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_select_linked(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select linked"; + ot->idname= "SEQUENCER_OT_select_linked"; + + /* api callbacks */ + ot->exec= sequencer_select_linked_exec; + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ +} + + +/* select handles operator */ +static int sequencer_select_handles_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, 0); + Sequence *seq; + int sel_side= RNA_enum_get(op->ptr, "side"); + + if (ed==NULL) + return OPERATOR_CANCELLED; + + for(seq= ed->seqbasep->first; seq; seq=seq->next) { + if (seq->flag & SELECT) { + switch(sel_side) { + case SEQ_SIDE_LEFT: + seq->flag &= ~SEQ_RIGHTSEL; + seq->flag |= SEQ_LEFTSEL; + break; + case SEQ_SIDE_RIGHT: + seq->flag &= ~SEQ_LEFTSEL; + seq->flag |= SEQ_RIGHTSEL; + break; + case SEQ_SIDE_BOTH: + seq->flag |= SEQ_LEFTSEL+SEQ_RIGHTSEL; + break; + } + } + } + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_select_handles(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Handles"; + ot->idname= "SEQUENCER_OT_select_handles"; + + /* api callbacks */ + ot->exec= sequencer_select_handles_exec; + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side of the handle that is selected"); +} + +/* select side operator */ +static int sequencer_select_active_side_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, 0); + Sequence *seq_act=get_last_seq(scene); + + if (ed==NULL || seq_act==NULL) + return OPERATOR_CANCELLED; + + seq_act->flag |= SELECT; + + select_active_side(ed->seqbasep, RNA_enum_get(op->ptr, "side"), seq_act->machine, seq_act->startdisp); + + ED_area_tag_redraw(CTX_wm_area(C)); + + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_select_active_side(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Active Side"; + ot->idname= "SEQUENCER_OT_select_active_side"; + + /* api callbacks */ + ot->exec= sequencer_select_active_side_exec; + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side of the handle that is selected"); +} + + +/* borderselect operator */ +static int sequencer_borderselect_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + Editing *ed= seq_give_editing(scene, FALSE); + View2D *v2d= UI_view2d_fromcontext(C); + + Sequence *seq; + rcti rect; + rctf rectf, rq; + int val; + short mval[2]; + + if(ed==NULL) + return OPERATOR_CANCELLED; + + val= RNA_int_get(op->ptr, "event_type"); + rect.xmin= RNA_int_get(op->ptr, "xmin"); + rect.ymin= RNA_int_get(op->ptr, "ymin"); + rect.xmax= RNA_int_get(op->ptr, "xmax"); + rect.ymax= RNA_int_get(op->ptr, "ymax"); + + mval[0]= rect.xmin; + mval[1]= rect.ymin; + UI_view2d_region_to_view(v2d, mval[0], mval[1], &rectf.xmin, &rectf.ymin); + mval[0]= rect.xmax; + mval[1]= rect.ymax; + UI_view2d_region_to_view(v2d, mval[0], mval[1], &rectf.xmax, &rectf.ymax); + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + seq_rectf(seq, &rq); + + if(BLI_isect_rctf(&rq, &rectf, 0)) { + if(val==LEFTMOUSE) seq->flag |= SELECT; + else seq->flag &= SEQ_DESEL; + recurs_sel_seq(seq); + } + } + + return OPERATOR_FINISHED; +} + + +/* ****** Border Select ****** */ +void SEQUENCER_OT_select_border(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Border Select"; + ot->idname= "SEQUENCER_OT_select_border"; + + /* api callbacks */ + ot->invoke= WM_border_select_invoke; + ot->exec= sequencer_borderselect_exec; + ot->modal= WM_border_select_modal; + + ot->poll= ED_operator_sequencer_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* rna */ + RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX); +} diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c new file mode 100644 index 00000000000..c7c92b71861 --- /dev/null +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -0,0 +1,301 @@ +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <stdio.h> + +#include "DNA_object_types.h" +#include "DNA_space_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" +#include "BLI_rand.h" + +#include "BKE_colortools.h" +#include "BKE_context.h" +#include "BKE_screen.h" +#include "BKE_sequence.h" + +#include "ED_space_api.h" +#include "ED_screen.h" + +#include "BIF_gl.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "ED_markers.h" + +#include "sequencer_intern.h" // own include + +/* ******************** manage regions ********************* */ + +ARegion *sequencer_has_buttons_region(ScrArea *sa) +{ + ARegion *ar, *arnew; + + for(ar= sa->regionbase.first; ar; ar= ar->next) + if(ar->regiontype==RGN_TYPE_UI) + return ar; + + /* add subdiv level; after header */ + for(ar= sa->regionbase.first; ar; ar= ar->next) + if(ar->regiontype==RGN_TYPE_HEADER) + break; + + /* is error! */ + if(ar==NULL) return NULL; + + arnew= MEM_callocN(sizeof(ARegion), "buttons for sequencer"); + + BLI_insertlinkafter(&sa->regionbase, ar, arnew); + arnew->regiontype= RGN_TYPE_UI; + arnew->alignment= RGN_ALIGN_RIGHT; + + arnew->flag = RGN_FLAG_HIDDEN; + + return arnew; +} + + +/* ******************** default callbacks for sequencer space ***************** */ + +static SpaceLink *sequencer_new(const bContext *C) +{ + Scene *scene= CTX_data_scene(C); + ARegion *ar; + SpaceSeq *sseq; + + sseq= MEM_callocN(sizeof(SpaceSeq), "initsequencer"); + sseq->spacetype= SPACE_SEQ; + sseq->zoom= 4; + sseq->chanshown = 0; + + + /* header */ + ar= MEM_callocN(sizeof(ARegion), "header for sequencer"); + + BLI_addtail(&sseq->regionbase, ar); + ar->regiontype= RGN_TYPE_HEADER; + ar->alignment= RGN_ALIGN_BOTTOM; + + /* buttons/list view */ + ar= MEM_callocN(sizeof(ARegion), "buttons for sequencer"); + + BLI_addtail(&sseq->regionbase, ar); + ar->regiontype= RGN_TYPE_UI; + ar->alignment= RGN_ALIGN_RIGHT; + ar->flag = RGN_FLAG_HIDDEN; + + /* main area */ + ar= MEM_callocN(sizeof(ARegion), "main area for sequencer"); + + BLI_addtail(&sseq->regionbase, ar); + ar->regiontype= RGN_TYPE_WINDOW; + + + /* seq space goes from (0,8) to (0, efra) */ + + ar->v2d.tot.xmin= 0.0f; + ar->v2d.tot.ymin= 0.0f; + ar->v2d.tot.xmax= scene->r.efra; + ar->v2d.tot.ymax= 8.0f; + + ar->v2d.cur= ar->v2d.tot; + + ar->v2d.min[0]= 10.0f; + ar->v2d.min[1]= 4.0f; + + ar->v2d.max[0]= MAXFRAMEF; + ar->v2d.max[1]= MAXSEQ; + + ar->v2d.minzoom= 0.01f; + ar->v2d.maxzoom= 100.0f; + + ar->v2d.scroll |= (V2D_SCROLL_BOTTOM|V2D_SCROLL_SCALE_HORIZONTAL); + ar->v2d.scroll |= (V2D_SCROLL_LEFT|V2D_SCROLL_SCALE_VERTICAL); + ar->v2d.keepzoom= 0; + ar->v2d.keeptot= 0; + ar->v2d.align= V2D_ALIGN_NO_NEG_Y; + + return (SpaceLink *)sseq; +} + +/* not spacelink itself */ +static void sequencer_free(SpaceLink *sl) +{ +// SpaceSeq *sseq= (SpaceSequencer*) sl; + +// XXX if(sseq->gpd) free_gpencil_data(sseq->gpd); + +} + + +/* spacetype; init callback */ +static void sequencer_init(struct wmWindowManager *wm, ScrArea *sa) +{ + +} + +static SpaceLink *sequencer_duplicate(SpaceLink *sl) +{ + SpaceSeq *sseqn= MEM_dupallocN(sl); + + /* clear or remove stuff from old */ +// XXX sseq->gpd= gpencil_data_duplicate(sseq->gpd); + + return (SpaceLink *)sseqn; +} + + + +/* add handlers, stuff you only do once or on area/region changes */ +static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar) +{ + ListBase *keymap; + + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); + + /* own keymap */ + keymap= WM_keymap_listbase(wm, "Sequencer", SPACE_SEQ, 0); /* XXX weak? */ + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); +} + + +/* add handlers, stuff you only do once or on area/region changes */ +static void sequencer_header_area_init(wmWindowManager *wm, ARegion *ar) +{ + ED_region_header_init(ar); +} + +static void sequencer_header_area_draw(const bContext *C, ARegion *ar) +{ + ED_region_header(C, ar); +} + +static void sequencer_main_area_listener(ARegion *ar, wmNotifier *wmn) +{ + /* context changes */ + switch(wmn->category) { + case NC_SCENE: + switch(wmn->data) { + case ND_FRAME: + case ND_MARKERS: + case ND_SEQUENCER: + ED_region_tag_redraw(ar); + break; + } + break; + } +} + +/* *********************** buttons region ************************ */ + +/* add handlers, stuff you only do once or on area/region changes */ +static void sequencer_buttons_area_init(wmWindowManager *wm, ARegion *ar) +{ + + ED_region_panels_init(wm, ar); + +} + +static void sequencer_buttons_area_draw(const bContext *C, ARegion *ar) +{ + ED_region_panels(C, ar, 1, NULL); +} + +static void sequencer_buttons_area_listener(ARegion *ar, wmNotifier *wmn) +{ + /* context changes */ + switch(wmn->category) { + + } +} +/* ************************************* */ + +/* only called once, from space/spacetypes.c */ +void ED_spacetype_sequencer(void) +{ + SpaceType *st= MEM_callocN(sizeof(SpaceType), "spacetype sequencer"); + ARegionType *art; + + st->spaceid= SPACE_SEQ; + + st->new= sequencer_new; + st->free= sequencer_free; + st->init= sequencer_init; + st->duplicate= sequencer_duplicate; + st->operatortypes= sequencer_operatortypes; + st->keymap= sequencer_keymap; + + /* regions: main window */ + art= MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); + art->regionid = RGN_TYPE_WINDOW; + art->init= sequencer_main_area_init; + art->draw= drawseqspace; + art->listener= sequencer_main_area_listener; + art->keymapflag= ED_KEYMAP_VIEW2D|ED_KEYMAP_FRAMES; + + BLI_addhead(&st->regiontypes, art); + + /* regions: listview/buttons */ + art= MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); + art->regionid = RGN_TYPE_UI; + art->minsizex= 220; // XXX + art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_FRAMES; + art->listener= sequencer_buttons_area_listener; + art->init= sequencer_buttons_area_init; + art->draw= sequencer_buttons_area_draw; + BLI_addhead(&st->regiontypes, art); + + /* Keep as python only for now + sequencer_buttons_register(art); + */ + + /* regions: header */ + art= MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); + art->regionid = RGN_TYPE_HEADER; + art->minsizey= HEADERY; + art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_VIEW2D|ED_KEYMAP_FRAMES; + + art->init= sequencer_header_area_init; + art->draw= sequencer_header_area_draw; + + BLI_addhead(&st->regiontypes, art); + + BKE_spacetype_register(st); +} + |