diff options
author | Ton Roosendaal <ton@blender.org> | 2009-01-13 14:41:52 +0300 |
---|---|---|
committer | Ton Roosendaal <ton@blender.org> | 2009-01-13 14:41:52 +0300 |
commit | d263911eac23e7cd037eeb5ed42c0a04fdab4447 (patch) | |
tree | 8ffc2a26cc980e687874adc153bfcafe7234bc27 /source/blender/editors/space_sequencer/sequencer_edit.c | |
parent | 806bc87a9747fb64c34d56046624ec12300a8408 (diff) |
2.5
Renamed sequencer file to conform editor specs.
Couldn't yesterday, svn refused for some reason :)
Diffstat (limited to 'source/blender/editors/space_sequencer/sequencer_edit.c')
-rw-r--r-- | source/blender/editors/space_sequencer/sequencer_edit.c | 3985 |
1 files changed, 3985 insertions, 0 deletions
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..d9a0f4817e2 --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -0,0 +1,3985 @@ +/** + * $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 "BIF_gl.h" +#include "BIF_glutil.h" + +#include "WM_types.h" + +#include "ED_anim_api.h" +#include "ED_space_api.h" +#include "ED_types.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 BIF_undo_push() {} +static void error() {} +static void waitcursor() {} +static void activate_fileselect() {} +static void std_rmouse_transform() {} +static int get_mbut() {return 0;} +static int pupmenu() {return 0;} +static int pupmenu_col() {return 0;} +static int okee() {return 0;} +static void *find_nearest_marker() {return NULL;} +static void deselect_markers() {} +static void transform_markers() {} +static void transform_seq_nomarker() {} +#define SCE_MARKERS 0 +/* XXX */ + + +#ifdef WIN32 +char last_imagename[FILE_MAXDIR+FILE_MAXFILE]= "c:\\"; +#else +char last_imagename[FILE_MAXDIR+FILE_MAXFILE]= "/"; +#endif + +char last_sounddir[FILE_MAXDIR+FILE_MAXFILE]= ""; + +#define SEQ_DESEL ~(SELECT+SEQ_LEFTSEL+SEQ_RIGHTSEL) + +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) +{ + if(!_last_seq_init) { + Editing *ed; + Sequence *seq; + Sequence *l_sel = NULL; + Sequence *l_act = NULL; + + ed= scene->ed; + if(!ed) return NULL; + + for(seq= ed->seqbasep->first; seq; seq=seq->next) { + if(seq->flag & SEQ_ACTIVE) + l_act = seq; + if(seq->flag & SELECT) + l_sel = seq; + } + + if (l_act) { + _last_seq = l_act; + } else { + _last_seq = l_sel; + } + + if (_last_seq) { + _last_seq->flag |= SEQ_ACTIVE; + } + + _last_seq_init = 1; + } + + return _last_seq; +} + +void set_last_seq(Sequence *seq) +{ + if (_last_seq_init && _last_seq) { + _last_seq->flag &= ~SEQ_ACTIVE; + } + + _last_seq = seq; + _last_seq_init = 1; + + if (_last_seq) { + _last_seq->flag |= SEQ_ACTIVE; + } +} + +void clear_last_seq() +{ + if (_last_seq_init && _last_seq) { + _last_seq->flag &= ~SEQ_ACTIVE; + } + _last_seq = NULL; + _last_seq_init = 0; +} + +Sequence *get_forground_frame_seq(Scene *scene, int frame) +{ + Editing *ed; + Sequence *seq, *best_seq=NULL; + int best_machine = -1; + ed= scene->ed; + if(!ed) return NULL; + + for (seq=ed->seqbasep->first; seq; seq= seq->next) { + if(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; +} + +/* seq funcs's for transforming internally + notice the difference between start/end and left/right. + + left and right are the bounds at which the sequence is rendered, +start and end are from the start and fixed length of the sequence. +*/ +int seq_tx_get_start(Sequence *seq) { + return seq->start; +} +int seq_tx_get_end(Sequence *seq) +{ + return seq->start+seq->len; +} + +int seq_tx_get_final_left(Sequence *seq, int metaclip) +{ + if (metaclip && seq->tmp) { + /* return the range clipped by the parents range */ + return MAX2( seq_tx_get_final_left(seq, 0), seq_tx_get_final_left((Sequence *)seq->tmp, 1) ); + } else { + return (seq->start - seq->startstill) + seq->startofs; + } + +} +int seq_tx_get_final_right(Sequence *seq, int metaclip) +{ + if (metaclip && seq->tmp) { + /* return the range clipped by the parents range */ + return MIN2( seq_tx_get_final_right(seq, 0), seq_tx_get_final_right((Sequence *)seq->tmp, 1) ); + } else { + return ((seq->start+seq->len) + seq->endstill) - seq->endofs; + } +} + +void seq_tx_set_final_left(Sequence *seq, int val) +{ + if (val < (seq)->start) { + seq->startstill = abs(val - (seq)->start); + (seq)->startofs = 0; + } else { + seq->startofs = abs(val - (seq)->start); + seq->startstill = 0; + } +} + +void seq_tx_set_final_right(Sequence *seq, int val) +{ + if (val > (seq)->start + (seq)->len) { + seq->endstill = abs(val - (seq->start + (seq)->len)); + (seq)->endofs = 0; + } else { + seq->endofs = abs(val - ((seq)->start + (seq)->len)); + seq->endstill = 0; + } +} + +/* check if one side can be transformed */ +int seq_tx_check_left(Sequence *seq) +{ + if (seq->flag & SELECT) { + if (seq->flag & SEQ_LEFTSEL) + return 1; + else if (seq->flag & SEQ_RIGHTSEL) + return 0; + + return 1; /* selected and neither left or right handles are, so let us move both */ + } + return 0; +} + +int seq_tx_check_right(Sequence *seq) +{ + if (seq->flag & SELECT) { + if (seq->flag & SEQ_RIGHTSEL) + return 1; + else if (seq->flag & SEQ_LEFTSEL) + return 0; + + return 1; /* selected and neither left or right handles are, so let us move both */ + } + return 0; +} + +/* used so we can do a quick check for single image seq + since they work a bit differently to normal image seq's (during transform) */ +int check_single_seq(Sequence *seq) +{ + if ( seq->len==1 && (seq->type == SEQ_IMAGE || seq->type == SEQ_COLOR)) + return 1; + else + return 0; +} + +static void fix_single_image_seq(Sequence *seq) +{ + int left, start, offset; + if (!check_single_seq(seq)) + return; + + /* make sure the image is always at the start since there is only one, + adjusting its start should be ok */ + left = seq_tx_get_final_left(seq, 0); + start = seq->start; + if (start != left) { + offset = left - start; + seq_tx_set_final_left( seq, seq_tx_get_final_left(seq, 0) - offset ); + seq_tx_set_final_right( seq, seq_tx_get_final_right(seq, 0) - offset ); + seq->start += offset; + } +} + +int test_overlap_seq(Scene *scene, Sequence *test) +{ + Sequence *seq; + Editing *ed; + + ed= scene->ed; + if(ed==NULL) return 0; + + seq= ed->seqbasep->first; + while(seq) { + if(seq!=test) { + if(test->machine==seq->machine) { + if(test->depth==seq->depth) { + if( (test->enddisp <= seq->startdisp) || (test->startdisp >= seq->enddisp) ); + else return 1; + } + } + } + seq= seq->next; + } + return 0; +} + +void shuffle_seq(Scene *scene, Sequence *test) +{ + Editing *ed; + Sequence *seq; + int a, start; + + ed= scene->ed; + if(ed==NULL) return; + + /* is there more than 1 select: only shuffle y */ + a=0; + seq= ed->seqbasep->first; + while(seq) { + if(seq->flag & SELECT) a++; + seq= seq->next; + } + + if(a<2 && test->type==SEQ_IMAGE) { + start= test->start; + + for(a= 1; a<50; a++) { + test->start= start+a; + calc_sequence(test); + if( test_overlap_seq(scene, test)==0) return; + test->start= start-a; + calc_sequence(test); + if( test_overlap_seq(scene, test)==0) return; + } + test->start= start; + } + + test->machine++; + calc_sequence(test); + while( test_overlap_seq(scene, test) ) { + if(test->machine >= MAXSEQ) { + error("There is no more space to add a sequence strip"); + + BLI_remlink(ed->seqbasep, test); + seq_free_sequence(test); + return; + } + test->machine++; + calc_sequence(test); + } +} + +static void change_plugin_seq(Scene *scene, char *str) /* called from fileselect */ +{ + 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( test_overlap_seq(scene, last_seq) ) shuffle_seq(scene, last_seq); + + BIF_undo_push("Load/Change Plugin, Sequencer"); +} + + +void boundbox_seq(Scene *scene, rctf *rect) +{ + Sequence *seq; + Editing *ed; + float min[2], max[2]; + + ed= scene->ed; + 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 sequence_is_free_transformable(Sequence * seq) +{ + return seq->type < SEQ_EFFECT + || (get_sequence_effect_num_inputs(seq->type) == 0); +} + +char mouse_cfra_side(View2D *v2d, int frame ) +{ + short mval[2]; + float xmouse, ymouse; +// getmouseco_areawin(mval); + + /* choose the side based on which side of the playhead the mouse is on */ + UI_view2d_region_to_view(v2d, mval[0], mval[1], &xmouse, &ymouse); + return (xmouse > frame) ? 'R' : 'L'; +} + +Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int sel) +{ +/* looks to the left on lr==1, to the right on lr==2 + sel - 0==unselected, 1==selected, -1==done care*/ + Sequence *seq; + Editing *ed; + + ed= scene->ed; + if(ed==NULL) return 0; + + if (sel>0) 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)) || (sel==0 && (seq->flag & SELECT)==0) )) + { + switch (lr) { + case 1: + if (test->startdisp == (seq->enddisp)) { + return seq; + } + break; + case 2: + if (test->enddisp == (seq->startdisp)) { + return seq; + } + break; + } + } + seq= seq->next; + } + return NULL; +} + +Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, int sel) +{ +/* looks to the left on lr==1, to the right on lr==2 + sel - 0==unselected, 1==selected, -1==done care*/ + Sequence *seq,*best_seq = NULL; + Editing *ed; + + int dist, best_dist; + best_dist = MAXFRAME*2; + + ed= scene->ed; + if(ed==NULL) return 0; + + 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 1: + if (seq->enddisp <= test->startdisp) { + dist = test->enddisp - seq->startdisp; + } + break; + case 2: + 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) +{ + Sequence *seq; + Editing *ed; + float x, y; + short mval[2]; + float pixelx; + float handsize; + float displen; + *hand= 0; + + ed= scene->ed; + if(ed==NULL) return 0; + + pixelx = (v2d->cur.xmax - v2d->cur.xmin)/(v2d->mask.xmax - v2d->mask.xmin); + +// getmouseco_areawin(mval); + 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(sequence_is_free_transformable(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= 1; + else if( -handsize+seq->enddisp <=x ) + *hand= 2; + } + } + 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; +} + +static void deselect_all_seq(Scene *scene) +{ + Sequence *seq; + Editing *ed; + + ed= scene->ed; + if(ed==NULL) return; + + SEQP_BEGIN(ed, seq) { + seq->flag &= SEQ_DESEL; + } + SEQ_END + + BIF_undo_push("(De)select all Strips, Sequencer"); +} + +static 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; + } +} + +void select_single_seq(Scene *scene, Sequence *seq, int deselect_all) +{ + if(deselect_all) + deselect_all_seq(scene); + set_last_seq(seq); + + if((seq->type==SEQ_IMAGE) || (seq->type==SEQ_MOVIE)) { + if(seq->strip) + strncpy(last_imagename, seq->strip->dir, FILE_MAXDIR-1); + } + else if((seq->type==SEQ_HD_SOUND) || (seq->type==SEQ_RAM_SOUND)) { + if(seq->strip) + strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1); + } + seq->flag|= SELECT; + recurs_sel_seq(seq); +} + +void swap_select_seq(Scene *scene) +{ + Sequence *seq; + Editing *ed; + int sel=0; + + ed= scene->ed; + if(ed==NULL) return; + + SEQP_BEGIN(ed, seq) { + if(seq->flag & SELECT) sel= 1; + } + SEQ_END + + SEQP_BEGIN(ed, seq) { + /* always deselect all to be sure */ + seq->flag &= SEQ_DESEL; + if(sel==0) seq->flag |= SELECT; + } + SEQ_END + + BIF_undo_push("Swap Selected Strips, Sequencer"); + +} + +void select_channel_direction(Scene *scene, Sequence *test,int lr) { +/* selects all strips in a channel to one direction of the passed strip */ + Sequence *seq; + Editing *ed; + + ed= scene->ed; + if(ed==NULL) return; + + seq= ed->seqbasep->first; + while(seq) { + if(seq!=test) { + if (test->machine==seq->machine) { + if(test->depth==seq->depth) { + if (((lr==1)&&(test->startdisp > (seq->startdisp)))||((lr==2)&&(test->startdisp < (seq->startdisp)))) { + seq->flag |= SELECT; + recurs_sel_seq(seq); + } + } + } + } + seq= seq->next; + } + test->flag |= SELECT; + recurs_sel_seq(test); +} + +void select_dir_from_last(Scene *scene, int lr) +{ + Sequence *seq=get_last_seq(scene); + if (seq==NULL) + return; + + select_channel_direction(scene, seq,lr); + + if (lr==1) BIF_undo_push("Select Strips to the Left, Sequencer"); + else BIF_undo_push("Select Strips to the Right, Sequencer"); +} + +void select_surrounding_handles(Scene *scene, Sequence *test) +{ + Sequence *neighbor; + + neighbor=find_neighboring_sequence(scene, test, 1, -1); + if (neighbor) { + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_RIGHTSEL; + } + neighbor=find_neighboring_sequence(scene, test, 2, -1); + if (neighbor) { + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_LEFTSEL; + } + test->flag |= SELECT; +} + +void select_surround_from_last(Scene *scene) +{ + Sequence *seq=get_last_seq(scene); + + if (seq==NULL) + return; + + select_surrounding_handles(scene, seq); + BIF_undo_push("Select Surrounding Handles, Sequencer"); +} + +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 1: + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_RIGHTSEL; + seq->flag |= SEQ_LEFTSEL; + break; + case 2: + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_LEFTSEL; + seq->flag |= SEQ_RIGHTSEL; + break; + } + seq->flag |= SELECT; + change = 1; + } + } + if (change) { + + if (lr==1) BIF_undo_push("Select Left Handles, Sequencer"); + else BIF_undo_push("Select Right Handles, Sequencer"); + } +} + +void mouse_select_seq(Scene *scene, View2D *v2d) +{ + Sequence *seq,*neighbor; + int hand,seldir, shift= 0; // XXX + TimeMarker *marker; + + marker=find_nearest_marker(SCE_MARKERS, 1); + + 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; + } + + BIF_undo_push("Select Strips, Sequencer"); + + } else { + + seq= find_nearest_seq(scene, v2d, &hand); + if(0) // !(G.qual & LR_SHIFTKEY)&&!(G.qual & LR_ALTKEY)&&!(G.qual & LR_CTRLKEY)) + deselect_all_seq(scene); + + if(seq) { + set_last_seq(seq); + + if ((seq->type == SEQ_IMAGE) || (seq->type == SEQ_MOVIE)) { + if(seq->strip) { + strncpy(last_imagename, seq->strip->dir, FILE_MAXDIR-1); + } + } else + if (seq->type == SEQ_HD_SOUND || seq->type == SEQ_RAM_SOUND) { + if(seq->strip) { + strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1); + } + } + + if(0) { // XXX (G.qual & LR_SHIFTKEY) && (seq->flag & SELECT)) { + if(hand==0) seq->flag &= SEQ_DESEL; + else if(hand==1) { + if(seq->flag & SEQ_LEFTSEL) + seq->flag &= ~SEQ_LEFTSEL; + else seq->flag |= SEQ_LEFTSEL; + } + else if(hand==2) { + if(seq->flag & SEQ_RIGHTSEL) + seq->flag &= ~SEQ_RIGHTSEL; + else seq->flag |= SEQ_RIGHTSEL; + } + } + else { + seq->flag |= SELECT; + if(hand==1) seq->flag |= SEQ_LEFTSEL; + if(hand==2) seq->flag |= SEQ_RIGHTSEL; + } + + /* On Ctrl-Alt selection, select the strip and bordering handles */ + if (0) { // XXX (G.qual & LR_CTRLKEY) && (G.qual & LR_ALTKEY)) { + // XXX if (!(G.qual & LR_SHIFTKEY)) deselect_all_seq(scene); + seq->flag |= SELECT; + select_surrounding_handles(scene, seq); + + /* Ctrl signals Left, Alt signals Right + 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. */ + } else if (0) { // XXX ((G.qual & LR_CTRLKEY) || (G.qual & LR_ALTKEY)) && (seq->flag & SELECT)) { + + if (0); // G.qual & LR_CTRLKEY) seldir=1; + else seldir=2; + neighbor=find_neighboring_sequence(scene, seq, seldir, -1); + if (neighbor) { + switch (seldir) { + case 1: + if ((seq->flag & SEQ_LEFTSEL)&&(neighbor->flag & SEQ_RIGHTSEL)) { +// XXX if (!(G.qual & LR_SHIFTKEY)) deselect_all_seq(scene); + select_channel_direction(scene, seq,1); + } else { + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_RIGHTSEL; + seq->flag |= SEQ_LEFTSEL; + } + break; + case 2: + if ((seq->flag & SEQ_RIGHTSEL)&&(neighbor->flag & SEQ_LEFTSEL)) { +// XXX if (!(G.qual & LR_SHIFTKEY)) deselect_all_seq(scene); + select_channel_direction(scene, seq,2); + } else { + neighbor->flag |= SELECT; + recurs_sel_seq(neighbor); + neighbor->flag |= SEQ_LEFTSEL; + seq->flag |= SEQ_RIGHTSEL; + } + break; + } + } else { +// XXX if (!(G.qual & LR_SHIFTKEY)) deselect_all_seq(scene); + select_channel_direction(scene, seq,seldir); + } + } + + recurs_sel_seq(seq); + } + + + BIF_undo_push("Select Strips, Sequencer"); + + std_rmouse_transform(transform_seq_nomarker); + } + + /* marker transform */ + 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; + } + } + } +} + + +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(seq); + + *( (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; +} + +static Sequence *sfile_to_sequence(Scene *scene, SpaceFile *sfile, int cfra, int machine, int last) +{ +#if 0 + /* XXX sfile recoded... */ + Sequence *seq; + Strip *strip; + StripElem *se; + int totsel, a; + char name[160]; + + /* are there selected files? */ + totsel= 0; + for(a=0; a<sfile->totfile; a++) { + if(sfile->filelist[a].flags & ACTIVE) { + if( (sfile->filelist[a].type & S_IFDIR)==0 ) { + totsel++; + } + } + } + + if(last) { + /* if not, a file handed to us? */ + if(totsel==0 && sfile->file[0]) totsel= 1; + } + + if(totsel==0) return 0; + + /* make seq */ + seq= alloc_sequence(((Editing *)scene->ed)->seqbasep, cfra, machine); + seq->len= totsel; + + if(totsel==1) { + seq->startstill= 25; + seq->endstill= 24; + } + + calc_sequence(seq); + + if(sfile->flag & FILE_STRINGCODE) { + strcpy(name, sfile->dir); + BLI_makestringcode(G.sce, name); + } else { + strcpy(name, sfile->dir); + } + + /* strip and stripdata */ + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strip->len= totsel; + strip->us= 1; + strncpy(strip->dir, name, FILE_MAXDIR-1); + strip->stripdata= se= MEM_callocN(totsel*sizeof(StripElem), "stripelem"); + + for(a=0; a<sfile->totfile; a++) { + if(sfile->filelist[a].flags & ACTIVE) { + if( (sfile->filelist[a].type & S_IFDIR)==0 ) { + strncpy(se->name, sfile->filelist[a].relname, FILE_MAXFILE-1); + se++; + } + } + } + /* no selected file: */ + if(totsel==1 && se==strip->stripdata) { + strncpy(se->name, sfile->file, FILE_MAXFILE-1); + } + + /* last active name */ + strncpy(last_imagename, seq->strip->dir, FILE_MAXDIR-1); + + return seq; +#endif + return NULL; +} + + +#if 0 +static int sfile_to_mv_sequence_load(Scene *scene, SpaceFile *sfile, int cfra, + int machine, int index ) +{ + /* XXX sfile recoded... */ + Sequence *seq; + struct anim *anim; + Strip *strip; + StripElem *se; + int totframe; + char name[160]; + char str[FILE_MAXDIR+FILE_MAXFILE]; + + totframe= 0; + + strncpy(str, sfile->dir, FILE_MAXDIR-1); + if(index<0) + strncat(str, sfile->file, FILE_MAXDIR-1); + else + strncat(str, sfile->filelist[index].relname, FILE_MAXDIR-1); + + /* is it a movie? */ + anim = openanim(str, IB_rect); + if(anim==0) { + error("The selected file is not a movie or " + "FFMPEG-support not compiled in!"); + return(cfra); + } + + totframe= IMB_anim_get_duration(anim); + + /* make seq */ + seq= alloc_sequence(((Editing *)scene->ed)->seqbasep, cfra, machine); + seq->len= totframe; + seq->type= SEQ_MOVIE; + seq->anim= anim; + seq->anim_preseek = IMB_anim_get_preseek(anim); + + calc_sequence(seq); + + if(sfile->flag & FILE_STRINGCODE) { + strcpy(name, sfile->dir); + BLI_makestringcode(G.sce, name); + } else { + strcpy(name, sfile->dir); + } + + /* strip and stripdata */ + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strip->len= totframe; + strip->us= 1; + strncpy(strip->dir, name, FILE_MAXDIR-1); + strip->stripdata= se= MEM_callocN(sizeof(StripElem), "stripelem"); + + /* name movie in first strip */ + if(index<0) + strncpy(se->name, sfile->file, FILE_MAXFILE-1); + else + strncpy(se->name, sfile->filelist[index].relname, FILE_MAXFILE-1); + + /* last active name */ + strncpy(last_imagename, seq->strip->dir, FILE_MAXDIR-1); + return(cfra+totframe); +} +#endif + +static void sfile_to_mv_sequence(SpaceFile *sfile, int cfra, int machine) +{ +#if 0 + /* XXX sfile recoded... */ + int a, totsel; + + totsel= 0; + for(a= 0; a<sfile->totfile; a++) { + if(sfile->filelist[a].flags & ACTIVE) { + if ((sfile->filelist[a].type & S_IFDIR)==0) { + totsel++; + } + } + } + + if((totsel==0) && (sfile->file[0])) { + cfra= sfile_to_mv_sequence_load(sfile, cfra, machine, -1); + return; + } + + if(totsel==0) return; + + /* ok. check all the select file, and load it. */ + for(a= 0; a<sfile->totfile; a++) { + if(sfile->filelist[a].flags & ACTIVE) { + if ((sfile->filelist[a].type & S_IFDIR)==0) { + /* load and update current frame. */ + cfra= sfile_to_mv_sequence_load(sfile, cfra, machine, a); + } + } + } +#endif +} + +static Sequence *sfile_to_ramsnd_sequence(Scene *scene, SpaceFile *sfile, int cfra, int machine) +{ +#if 0 + /* XXX sfile recoded... */ + Sequence *seq; + bSound *sound; + Strip *strip; + StripElem *se; + double totframe; + char name[160]; + char str[256]; + + totframe= 0.0; + + strncpy(str, sfile->dir, FILE_MAXDIR-1); + strncat(str, sfile->file, FILE_MAXFILE-1); + + sound= sound_new_sound(str); + if (!sound || sound->sample->type == SAMPLE_INVALID) { + error("Unsupported audio format"); + return 0; + } + if (sound->sample->bits != 16) { + error("Only 16 bit audio is supported"); + return 0; + } + sound->id.us=1; + sound->flags |= SOUND_FLAGS_SEQUENCE; + audio_makestream(sound); + + totframe= (int) ( ((float)(sound->streamlen-1)/ + ( (float)scene->r.audio.mixrate*4.0 ))* FPS); + + /* make seq */ + seq= alloc_sequence(((Editing *)scene->ed)->seqbasep, cfra, machine); + seq->len= totframe; + seq->type= SEQ_RAM_SOUND; + seq->sound = sound; + + calc_sequence(seq); + + if(sfile->flag & FILE_STRINGCODE) { + strcpy(name, sfile->dir); + BLI_makestringcode(G.sce, name); + } else { + strcpy(name, sfile->dir); + } + + /* strip and stripdata */ + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strip->len= totframe; + strip->us= 1; + strncpy(strip->dir, name, FILE_MAXDIR-1); + strip->stripdata= se= MEM_callocN(sizeof(StripElem), "stripelem"); + + /* name sound in first strip */ + strncpy(se->name, sfile->file, FILE_MAXFILE-1); + + /* last active name */ + strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1); + + return seq; +#endif + return NULL; +} + +#if 0 +static int sfile_to_hdsnd_sequence_load(SpaceFile *sfile, int cfra, + int machine, int index) +{ + /* XXX sfile recoded... */ + Sequence *seq; + struct hdaudio *hdaudio; + Strip *strip; + StripElem *se; + int totframe; + char name[160]; + char str[FILE_MAXDIR+FILE_MAXFILE]; + + totframe= 0; + + strncpy(str, sfile->dir, FILE_MAXDIR-1); + if(index<0) + strncat(str, sfile->file, FILE_MAXDIR-1); + else + strncat(str, sfile->filelist[index].relname, FILE_MAXDIR-1); + + /* is it a sound file? */ + hdaudio = sound_open_hdaudio(str); + if(hdaudio==0) { + error("The selected file is not a sound file or " + "FFMPEG-support not compiled in!"); + return(cfra); + } + + totframe= sound_hdaudio_get_duration(hdaudio, FPS); + + /* make seq */ + seq= alloc_sequence(((Editing *)scene->ed)->seqbasep, cfra, machine); + seq->len= totframe; + seq->type= SEQ_HD_SOUND; + seq->hdaudio= hdaudio; + + calc_sequence(seq); + + if(sfile->flag & FILE_STRINGCODE) { + strcpy(name, sfile->dir); + BLI_makestringcode(G.sce, name); + } else { + strcpy(name, sfile->dir); + } + + /* strip and stripdata */ + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strip->len= totframe; + strip->us= 1; + strncpy(strip->dir, name, FILE_MAXDIR-1); + strip->stripdata= se= MEM_callocN(sizeof(StripElem), "stripelem"); + + /* name movie in first strip */ + if(index<0) + strncpy(se->name, sfile->file, FILE_MAXFILE-1); + else + strncpy(se->name, sfile->filelist[index].relname, FILE_MAXFILE-1); + + /* last active name */ + strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1); + return(cfra+totframe); +} +#endif + +static void sfile_to_hdsnd_sequence(SpaceFile *sfile, int cfra, int machine) +{ +#if 0 + /* XXX sfile recoded... */ + int totsel, a; + + totsel= 0; + for(a= 0; a<sfile->totfile; a++) { + if(sfile->filelist[a].flags & ACTIVE) { + if((sfile->filelist[a].type & S_IFDIR)==0) { + totsel++; + } + } + } + + if((totsel==0) && (sfile->file[0])) { + cfra= sfile_to_hdsnd_sequence_load(sfile, cfra, machine, -1); + return; + } + + if(totsel==0) return; + + /* ok, check all the select file, and load it. */ + for(a= 0; a<sfile->totfile; a++) { + if(sfile->filelist[a].flags & ACTIVE) { + if((sfile->filelist[a].type & S_IFDIR)==0) { + /* load and update current frame. */ + cfra= sfile_to_hdsnd_sequence_load(sfile, cfra, machine, a); + } + } + } +#endif +} + + +static void add_image_strips(Scene *scene, char *name) +{ +#if 0 + /* XXX sfile recoded... */ + + SpaceFile *sfile; + struct direntry *files; + float x, y; + int a, totfile, cfra, machine; + short mval[2]; + + deselect_all_seq(scene); + + /* restore windowmatrices */ +// XXX drawseqspace(curarea, curarea->spacedata.first); + + /* search sfile */ +// sfile= scrarea_find_space_of_type(curarea, SPACE_FILE); + if(sfile==0) return; + + /* where will it be */ +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + cfra= (int)(x+0.5); + machine= (int)(y+0.5); + + waitcursor(1); + + /* also read contents of directories */ + files= sfile->filelist; + totfile= sfile->totfile; + sfile->filelist= 0; + sfile->totfile= 0; + + for(a=0; a<totfile; a++) { + if(files[a].flags & ACTIVE) { + if( (files[a].type & S_IFDIR) ) { + strncat(sfile->dir, files[a].relname, FILE_MAXFILE-1); + strcat(sfile->dir,"/"); + read_dir(sfile); + + /* select all */ + swapselect_file(sfile); + + if ( sfile_to_sequence(scene, sfile, cfra, machine, 0) ) machine++; + + parent(sfile); + } + } + } + + sfile->filelist= files; + sfile->totfile= totfile; + + /* read directory itself */ + sfile_to_sequence(scene, sfile, cfra, machine, 1); + + waitcursor(0); + + BIF_undo_push("Add Image Strip, Sequencer"); + transform_seq_nomarker('g', 0); +#endif +} + +static void add_movie_strip(Scene *scene, View2D *v2d, char *name) +{ + + /* XXX sfile recoded... */ + SpaceFile *sfile; + float x, y; + int cfra, machine; + short mval[2]; + + deselect_all_seq(scene); + + /* restore windowmatrices */ +// drawseqspace(curarea, curarea->spacedata.first); + + /* search sfile */ +// sfile= scrarea_find_space_of_type(curarea, SPACE_FILE); + if(sfile==0) return; + + /* where will it be */ +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + cfra= (int)(x+0.5); + machine= (int)(y+0.5); + + waitcursor(1); + + /* read directory itself */ + sfile_to_mv_sequence(sfile, cfra, machine); + + waitcursor(0); + + BIF_undo_push("Add Movie Strip, Sequencer"); + transform_seq_nomarker('g', 0); + +} + +static void add_movie_and_hdaudio_strip(Scene *scene, View2D *v2d, char *name) +{ + SpaceFile *sfile; + float x, y; + int cfra, machine; + short mval[2]; + + deselect_all_seq(scene); + + /* restore windowmatrices */ +// areawinset(curarea->win); +// drawseqspace(curarea, curarea->spacedata.first); + + /* search sfile */ +// sfile= scrarea_find_space_of_type(curarea, SPACE_FILE); + if(sfile==0) return; + + /* where will it be */ +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + cfra= (int)(x+0.5); + machine= (int)(y+0.5); + + waitcursor(1); + + /* read directory itself */ + sfile_to_hdsnd_sequence(sfile, cfra, machine); + sfile_to_mv_sequence(sfile, cfra, machine); + + waitcursor(0); + + BIF_undo_push("Add Movie and HD-Audio Strip, Sequencer"); + transform_seq_nomarker('g', 0); + +} + +static void add_sound_strip_ram(Scene *scene, View2D *v2d, char *name) +{ + SpaceFile *sfile; + float x, y; + int cfra, machine; + short mval[2]; + + deselect_all_seq(scene); + +// sfile= scrarea_find_space_of_type(curarea, SPACE_FILE); + if (sfile==0) return; + + /* where will it be */ +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + cfra= (int)(x+0.5); + machine= (int)(y+0.5); + + waitcursor(1); + + sfile_to_ramsnd_sequence(scene, sfile, cfra, machine); + + waitcursor(0); + + BIF_undo_push("Add Sound (RAM) Strip, Sequencer"); + transform_seq_nomarker('g', 0); +} + +static void add_sound_strip_hd(Scene *scene, View2D *v2d, char *name) +{ + SpaceFile *sfile; + float x, y; + int cfra, machine; + short mval[2]; + + deselect_all_seq(scene); + +// sfile= scrarea_find_space_of_type(curarea, SPACE_FILE); + if (sfile==0) return; + + /* where will it be */ +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + cfra= (int)(x+0.5); + machine= (int)(y+0.5); + + waitcursor(1); + + sfile_to_hdsnd_sequence(sfile, cfra, machine); + + waitcursor(0); + + BIF_undo_push("Add Sound (HD) Strip, Sequencer"); + transform_seq_nomarker('g', 0); +} + +static void add_scene_strip(Scene *scene, View2D *v2d, short event) +{ + Sequence *seq; + Strip *strip; + float x, y; + int cfra, machine; + short mval[2]; + + if(event> -1) { + int nr= 1; + Scene * sce= G.main->scene.first; + while(sce) { + if( event==nr) break; + nr++; + sce= sce->id.next; + } + if(sce) { + + deselect_all_seq(scene); + + /* where ? */ +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + cfra= (int)(x+0.5); + machine= (int)(y+0.5); + + seq= alloc_sequence(((Editing *)scene->ed)->seqbasep, cfra, machine); + seq->type= SEQ_SCENE; + seq->scene= sce; + seq->sfra= sce->r.sfra; + seq->len= sce->r.efra - sce->r.sfra + 1; + + seq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strncpy(seq->name + 2, sce->id.name + 2, + sizeof(seq->name) - 2); + strip->len= seq->len; + strip->us= 1; + + BIF_undo_push("Add Scene Strip, Sequencer"); + transform_seq_nomarker('g', 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(seq); + BLI_remlink(ed->seqbasep, seq); + + seq= ed->seqbasep->first; + + } + + waitcursor(0); + +} +#endif + +static void reload_image_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_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); + 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(seq); + BLI_remlink(ed->seqbasep, seq); + + update_changed_seq_and_deps(scene, seqact, 1, 1); + } + waitcursor(0); + +} + +static 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; +} + +static int seq_effect_find_selected(Scene *scene, Sequence *activeseq, int type, Sequence **selseq1, Sequence **selseq2, Sequence **selseq3) +{ + Editing *ed = scene->ed; + Sequence *seq1= 0, *seq2= 0, *seq3= 0, *seq; + + 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("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("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; + case 1: + if(seq2==0) { + error("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("Need 2 selected sequence strips"); + return 0; + } + if(seq3==0) seq3= seq2; + } + + if (seq1==NULL && seq2==NULL && seq3==NULL) return 0; + + *selseq1= seq1; + *selseq2= seq2; + *selseq3= seq3; + + return 1; +} + +static int add_seq_effect(Scene *scene, View2D *v2d, int type, char *str) +{ + Editing *ed; + Sequence *newseq, *seq1, *seq2, *seq3; + Strip *strip; + float x, y; + int cfra, machine; + short mval[2]; + struct SeqEffectHandle sh; + + if(scene->ed==NULL) return 0; + ed= scene->ed; + + if(!seq_effect_find_selected(scene, NULL, event_to_efftype(type), &seq1, &seq2, &seq3)) + return 0; + + deselect_all_seq(scene); + + /* where will it be (cfra is not realy needed) */ +// getmouseco_areawin(mval); + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + cfra= (int)(x+0.5); + machine= (int)(y+0.5); + + /* allocate and initialize */ + newseq= alloc_sequence(((Editing *)scene->ed)->seqbasep, cfra, machine); + newseq->type= event_to_efftype(type); + + sh = get_sequence_effect(newseq); + + newseq->seq1= seq1; + newseq->seq2= seq2; + newseq->seq3= seq3; + + sh.init(newseq); + + if (!seq1) { + newseq->len= 1; + newseq->startstill= 25; + newseq->endstill= 24; + } + + calc_sequence(newseq); + + newseq->strip= strip= MEM_callocN(sizeof(Strip), "strip"); + strip->len= newseq->len; + strip->us= 1; + if(newseq->len>0) + strip->stripdata= MEM_callocN(newseq->len*sizeof(StripElem), "stripelem"); + + /* initialize plugin */ + if(newseq->type == SEQ_PLUGIN) { + sh.init_plugin(newseq, str); + + if(newseq->plugin==0) { + BLI_remlink(ed->seqbasep, newseq); + seq_free_sequence(newseq); + set_last_seq(NULL); + return 0; + } + } + + /* set find a free spot to but the strip */ + if (newseq->seq1) { + newseq->machine= MAX3(newseq->seq1->machine, + newseq->seq2->machine, + newseq->seq3->machine); + } + if(test_overlap_seq(scene, newseq)) shuffle_seq(scene, newseq); + + update_changed_seq_and_deps(scene, newseq, 1, 1); + + /* push undo and go into grab mode */ + if(newseq->type == SEQ_PLUGIN) { + BIF_undo_push("Add Plugin Strip, Sequencer"); + } else { + BIF_undo_push("Add Effect Strip, Sequencer"); + } + + transform_seq_nomarker('g', 0); + + return 1; +} + +static void load_plugin_seq(Scene *scene, View2D *v2d, char *str) /* called from fileselect */ +{ + add_seq_effect(scene, v2d, 10, str); +} + +void add_sequence(Scene *scene, View2D *v2d, int type) +{ + Editing *ed; + short event; + char *str; + + if (type >= 0){ + /* bypass pupmenu for calls from menus (aphex) */ + switch(type){ + case SEQ_SCENE: + event = 101; + break; + case SEQ_IMAGE: + event = 1; + break; + case SEQ_MOVIE: + event = 102; + break; + case SEQ_RAM_SOUND: + event = 103; + break; + case SEQ_HD_SOUND: + event = 104; + break; + case SEQ_MOVIE_AND_HD_SOUND: + event = 105; + break; + case SEQ_PLUGIN: + event = 10; + break; + case SEQ_CROSS: + event = 2; + break; + case SEQ_ADD: + event = 4; + break; + case SEQ_SUB: + event = 5; + break; + case SEQ_ALPHAOVER: + event = 7; + break; + case SEQ_ALPHAUNDER: + event = 8; + break; + case SEQ_GAMCROSS: + event = 3; + break; + case SEQ_MUL: + event = 6; + break; + case SEQ_OVERDROP: + event = 9; + break; + case SEQ_WIPE: + event = 13; + break; + case SEQ_GLOW: + event = 14; + break; + case SEQ_TRANSFORM: + event = 15; + break; + case SEQ_COLOR: + event = 16; + break; + case SEQ_SPEED: + event = 17; + break; + default: + event = 0; + break; + } + } + else { + event= pupmenu("Add Sequence Strip%t" + "|Image Sequence%x1" + "|Movie%x102" +#ifdef WITH_FFMPEG + "|Movie + Audio (HD)%x105" + "|Audio (RAM)%x103" + "|Audio (HD)%x104" +#else + "|Audio (Wav)%x103" +#endif + "|Scene%x101" + "|Plugin%x10" + "|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" + "|Transforms%x15" + "|Color Generator%x16" + "|Speed Control%x17"); + } + + if(event<1) return; + + if(scene->ed==NULL) { + ed= scene->ed= MEM_callocN( sizeof(Editing), "addseq"); + ed->seqbasep= &ed->seqbase; + } + else ed= scene->ed; + + switch(event) { + case 1: + /* Image Dosnt work at the moment - TODO */ + //if(G.qual & LR_CTRLKEY) + // activate_imageselect(FILE_SPECIAL, "Select Images", last_imagename, add_image_strips); + //else + activate_fileselect(FILE_SPECIAL, "Select Images", last_imagename, add_image_strips); + break; + case 105: + activate_fileselect(FILE_SPECIAL, "Select Movie+Audio", last_imagename, add_movie_and_hdaudio_strip); + break; + case 102: + + activate_fileselect(FILE_SPECIAL, "Select Movie", last_imagename, add_movie_strip); + break; + case 101: + /* new menu: */ + IDnames_to_pupstring(&str, NULL, NULL, &G.main->scene, (ID *)scene, NULL); + + add_scene_strip(scene, v2d, pupmenu_col(str, 20)); + + MEM_freeN(str); + + break; + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 13: + case 14: + case 15: + case 16: + case 17: + if(get_last_seq(scene)==0 && + get_sequence_effect_num_inputs( event_to_efftype(event))> 0) + error("Need at least one active sequence strip"); + else if(event==10) + activate_fileselect(FILE_SPECIAL, "Select Plugin", U.plugseqdir, load_plugin_seq); + else + add_seq_effect(scene, v2d, event, NULL); + + break; + case 103: + if (!last_sounddir[0]) strncpy(last_sounddir, U.sounddir, FILE_MAXDIR-1); + activate_fileselect(FILE_SPECIAL, "Select Audio (RAM)", last_sounddir, add_sound_strip_ram); + break; + case 104: + if (!last_sounddir[0]) strncpy(last_sounddir, U.sounddir, FILE_MAXDIR-1); + activate_fileselect(FILE_SPECIAL, "Select Audio (HD)", last_sounddir, add_sound_strip_hd); + break; + } +} + +void change_sequence(Scene *scene) +{ + 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); + BIF_undo_push("Change Strip Effect, Sequencer"); + } + } + else if(last_seq->type == SEQ_IMAGE) { + if(okee("Change images")) { + activate_fileselect(FILE_SPECIAL, + "Select Images", + last_imagename, + 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); + + } + } + +} + +void reload_sequence(Scene *scene) +{ + Editing *ed= scene->ed; + Sequence *seq; + + SEQP_BEGIN(ed, seq) { + if(seq->flag & SELECT) { + update_changed_seq_and_deps(scene, seq, 0, 1); + } + } + SEQ_END +} + +void reassign_inputs_seq_effect(Scene *scene) +{ + Editing *ed= scene->ed; + Sequence *seq1, *seq2, *seq3, *last_seq = get_last_seq(scene); + + 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)) + 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)) { + error("Can't reassign inputs: no cycles allowed"); + 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) +{ + 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(0); + if(seq->type==SEQ_META) recurs_del_seq_flag(scene, &seq->seqbase, flag, 1); + if(seq->ipo) seq->ipo->id.us--; + seq_free_sequence(seq); + } + seq= seqn; + } +} + +void del_seq(Scene *scene) +{ + Sequence *seq; + MetaStack *ms; + Editing *ed; + int nothingSelected = TRUE; + + ed= scene->ed; + if(ed==NULL) return; + + 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 || okee("Erase selected")==0) return; + + /* 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; + } + + BIF_undo_push("Delete Strip(s), Sequencer"); +} + +static Sequence *dupli_seq(Sequence *seq) +{ + Sequence *seqn = MEM_dupallocN(seq); + + seq->tmp = seqn; + + seqn->strip= MEM_dupallocN(seq->strip); + + if(seqn->ipo) seqn->ipo->id.us++; + + 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"); + } + + seqn->flag &= ~SEQ_ACTIVE; + + 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(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; +} + +void seq_cut(Scene *scene, View2D *v2d, int cutframe, int hard_cut) +{ + Editing *ed; + ListBase newlist; + char side; + int did_something; + + ed= scene->ed; + if(ed==NULL) return; + + newlist.first= newlist.last= NULL; + + if (hard_cut) { + did_something = cut_seq_list(scene, + ed->seqbasep, &newlist, cutframe, cut_seq_hard); + } else { + did_something = cut_seq_list(scene, + ed->seqbasep, &newlist, cutframe, cut_seq_soft); + } + + if (newlist.first) { /* got new strips ? */ + Sequence *seq; + addlisttolist(ed->seqbasep, &newlist); + + + /* change the selection, not strictly needed but nice */ + side = mouse_cfra_side(v2d, cutframe); + + SEQP_BEGIN(ed, seq) { + if (side=='L') { + if ( seq->startdisp >= cutframe ) { + seq->flag &= ~SELECT; + } + } else { + if ( seq->enddisp <= cutframe ) { + seq->flag &= ~SELECT; + } + } + } + SEQ_END; + + /* as last: */ + sort_seq(scene); + } + if (did_something) { + BIF_undo_push("Cut Strips, Sequencer"); + } +} + +void add_duplicate_seq(Scene *scene) +{ + Editing *ed; + ListBase new; + + ed= scene->ed; + if(ed==NULL) return; + + new.first= new.last= 0; + + recurs_dupli_seq(scene, ed->seqbasep, &new); + addlisttolist(ed->seqbasep, &new); + + BIF_undo_push("Add Duplicate, Sequencer"); + transform_seq_nomarker('g', 0); +} + +int insert_gap(Scene *scene, int gap, int cfra) +{ + Sequence *seq; + Editing *ed; + int done=0; + + /* all strips >= cfra are shifted */ + ed= scene->ed; + 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; + char str[256]; + + /* touch all strips with movies */ + ed= scene->ed; + 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; + + ed= scene->ed; + 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; + char from[FILE_MAX], to[FILE_MAX], stripped[FILE_MAX]; + + ed= scene->ed; + if(ed==NULL || 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 + + BIF_undo_push("Remap Paths, Sequencer"); +} + + +void no_gaps(Scene *scene) +{ + Editing *ed; + int cfra, first= 0, done; + + ed= scene->ed; + 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; + } + } + + BIF_undo_push("No Gaps, Sequencer"); +} + + +/* ****************** META ************************* */ + +void make_meta(Scene *scene) +{ + Sequence *seq, *seqm, *next; + Editing *ed; + int tot; + + ed= scene->ed; + if(ed==NULL) return; + + /* 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) { + error("Can't make Meta Strip from audio"); + return; + } + } + seq= seq->next; + } + if(tot < 1) return; + + if(okee("Make Meta Strip")==0) return; + + /* 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) { + error("Please select all related strips"); + return; + } + + /* remove all selected from main list, and put in meta */ + + seqm= alloc_sequence(((Editing *)scene->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; + + if( test_overlap_seq(scene, seqm) ) shuffle_seq(scene, seqm); + + BIF_undo_push("Make Meta Strip, Sequencer"); +} + +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; +} + +void un_meta(Scene *scene) +{ + Editing *ed; + Sequence *seq, *last_seq = get_last_seq(scene); + + ed= scene->ed; + if(ed==NULL) return; + + if(last_seq==0 || last_seq->type!=SEQ_META) return; + + if(okee("Un Meta Strip")==0) return; + + 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(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( test_overlap_seq(scene, seq) ) { + shuffle_seq(scene, seq); + } + } + } + SEQ_END; + + sort_seq(scene); + + BIF_undo_push("Un-Make Meta Strip, Sequencer"); +} + +void exit_meta(Scene *scene) +{ + Sequence *seq; + MetaStack *ms; + Editing *ed; + + ed= scene->ed; + if(ed==NULL) return; + + if(ed->metastack.first==0) return; + + ms= ed->metastack.last; + BLI_remlink(&ed->metastack, ms); + + ed->seqbasep= ms->oldbasep; + + /* recalc all: the meta can have effects connected to it */ + seq= ed->seqbasep->first; + while(seq) { + calc_sequence(seq); + seq= seq->next; + } + + set_last_seq(ms->parseq); + + ms->parseq->flag |= SELECT; + recurs_sel_seq(ms->parseq); + + MEM_freeN(ms); + + BIF_undo_push("Exit Meta Strip, Sequence"); +} + + +void enter_meta(Scene *scene) +{ + MetaStack *ms; + Editing *ed; + Sequence *last_seq= get_last_seq(scene); + + ed= scene->ed; + if(ed==NULL) return; + + if(last_seq==0 || last_seq->type!=SEQ_META || (last_seq->flag & SELECT)==0) { + exit_meta(scene); + return; + } + + 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(NULL); + BIF_undo_push("Enter Meta Strip, Sequence"); +} + + +/* ****************** END META ************************* */ + +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); +} + +/* use to impose limits when dragging/extending - so impossible situations dont happen */ +static void transform_grab_xlimits(Sequence *seq, int leftflag, int rightflag) +{ + if(leftflag) { + if (seq_tx_get_final_left(seq, 0) >= seq_tx_get_final_right(seq, 0)) { + seq_tx_set_final_left(seq, seq_tx_get_final_right(seq, 0)-1); + } + + if (check_single_seq(seq)==0) { + if (seq_tx_get_final_left(seq, 0) >= seq_tx_get_end(seq)) { + seq_tx_set_final_left(seq, seq_tx_get_end(seq)-1); + } + + /* dosnt work now - TODO */ + /* + if (seq_tx_get_start(seq) >= seq_tx_get_final_right(seq, 0)) { + int ofs; + ofs = seq_tx_get_start(seq) - seq_tx_get_final_right(seq, 0); + seq->start -= ofs; + seq_tx_set_final_left(seq, seq_tx_get_final_left(seq, 0) + ofs ); + }*/ + + } + } + + if(rightflag) { + if (seq_tx_get_final_right(seq, 0) <= seq_tx_get_final_left(seq, 0)) { + seq_tx_set_final_right(seq, seq_tx_get_final_left(seq, 0)+1); + } + + if (check_single_seq(seq)==0) { + if (seq_tx_get_final_right(seq, 0) <= seq_tx_get_start(seq)) { + seq_tx_set_final_right(seq, seq_tx_get_start(seq)+1); + } + } + } + + /* sounds cannot be extended past their endpoints */ + if (seq->type == SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND) { + seq->startstill= 0; + seq->endstill= 0; + } +} + +static int can_transform_seq_test_func(Sequence * seq) +{ + if((seq->flag & SELECT) && !(seq->depth==0 && seq->flag & SEQ_LOCK)) { + return BUILD_SEQAR_COUNT_CURRENT | BUILD_SEQAR_COUNT_CHILDREN; + } + if ((seq->depth==0 && seq->flag & SEQ_LOCK) && !(seq->type & SEQ_EFFECT)) { + if (seq->type != SEQ_META) { + return BUILD_SEQAR_COUNT_NOTHING; + } else { + return BUILD_SEQAR_COUNT_CURRENT; + } + } + return BUILD_SEQAR_COUNT_CURRENT | BUILD_SEQAR_COUNT_CHILDREN; +} + +void transform_seq(Scene *scene, SpaceSeq *sseq, View2D *v2d, int mode, int context) +{ + Sequence *seq, *last_seq; + Editing *ed; + float dx, dy, dvec[2], div; + TransSeq *transmain, *ts; + int totstrip=0, firsttime=1, afbreek=0, midtog= 0, proj= 0; + int ix, iy; /* these values are used for storing the mouses offset from its original location */ + int ix_old = 0; + unsigned short event = 0; + short mval[2], xo, yo, xn, yn; + char str[32]; + char side= 'L'; /* for extend mode only - use to know which side to extend on */ + char marker_moved=0; /* if we mvoed a marker, redraw all marker views */ + /* used for extend in a number of places */ + int cfra = CFRA; + + /* for snapping */ + char snapskip = 0, snap, snap_old= 0; + int snapdist_max = seq_get_snaplimit(v2d); + /* at the moment there are only 4 possible snap points, + - last_seq (start,end) + - selected bounds (start/end) + - last_seq (next/prev) + - current frame */ + int snap_points[4], snap_point_num = 0; + int j; /* loop on snap_points */ + + /* for markers */ + int *oldframe = NULL, totmark=0, a; + TimeMarker *marker; + + /* looping on sequences, WHILE_SEQ macro allocates memory each time */ + int totseq_index, seq_index; + Sequence **seqar = 0; + + if(mode!='g' && mode!='e') return; /* from gesture */ + + /* which seqs are involved */ + ed= scene->ed; + if(ed==NULL) return; + + /* Build the sequence array once, be sure to free it */ + build_seqar_cb( ed->seqbasep, &seqar, &totseq_index, + can_transform_seq_test_func ); + + if (seqar) { + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if((seq->flag & SELECT) && !(seq->depth==0 && seq->flag & SEQ_LOCK)) + totstrip++; + /* only needed for extend but can set here anyway since were alredy looping */ + seq->tmp= NULL; + } + } + + /* for extending we need the metastrip clipped left/right values, set the metastrips as parents in seq->tmp */ + if (mode=='e') { + Sequence *meta_seq; + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if (seq->type == SEQ_META) { + for (meta_seq = seq->seqbase.first; meta_seq; meta_seq= meta_seq->next){ + meta_seq->tmp= (void *)seq; + } + } + } + } + + + if (sseq->flag & SEQ_MARKER_TRANS) { + for(marker= scene->markers.first; marker; marker= marker->next) { + if(marker->flag & SELECT) totmark++; + } + } + + if(totstrip==0 && totmark==0) { + if(seqar) MEM_freeN(seqar); + return; + } + + G.moving= 1; + + last_seq = get_last_seq(scene); + + ts=transmain= MEM_callocN(totstrip*sizeof(TransSeq), "transseq"); + + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if((seq->flag & SELECT) && !(seq->depth==0 && seq->flag & SEQ_LOCK)) { + ts->start= seq->start; + ts->machine= seq->machine; + ts->startstill= seq->startstill; + ts->endstill= seq->endstill; + ts->startofs= seq->startofs; + ts->endofs= seq->endofs; + + /* for extend only */ + if (mode=='e') { + ts->final_left = seq_tx_get_final_left(seq, 1); + ts->final_right = seq_tx_get_final_right(seq, 1); + } + ts++; + } + } + +// getmouseco_areawin(mval); + + /* choose the side based on which side of the playhead the mouse is on */ + if (mode=='e') + side = mouse_cfra_side(v2d, cfra); + + /* Markers */ + if (sseq->flag & SEQ_MARKER_TRANS && totmark) { + oldframe= MEM_mallocN(totmark*sizeof(int), "marker array"); + for(a=0, marker= scene->markers.first; marker; marker= marker->next) { + if(marker->flag & SELECT) { + if (mode=='e') { + + /* when extending, invalidate markers on the other side by using an invalid frame value */ + if ((side == 'L' && marker->frame > cfra) || (side == 'R' && marker->frame < cfra)) { + oldframe[a] = MAXFRAME+1; + } else { + oldframe[a]= marker->frame; + } + } else { + oldframe[a]= marker->frame; + } + a++; + } + } + } + + xo=xn= mval[0]; + yo=yn= mval[1]; + dvec[0]= dvec[1]= 0.0; + + while(afbreek==0) { +// getmouseco_areawin(mval); + // XXX G.qual = get_qual(); + // snap = (G.qual & LR_CTRLKEY) ? 1 : 0; + + if(mval[0]!=xo || mval[1]!=yo || firsttime || snap != snap_old) { + if (firsttime) { + snap_old = snap; + firsttime= 0; + } + + /* run for either grab or extend */ + dx= mval[0]- xo; + dy= mval[1]- yo; + + div= v2d->mask.xmax-v2d->mask.xmin; + dx= (v2d->cur.xmax-v2d->cur.xmin)*(dx)/div; + + div= v2d->mask.ymax-v2d->mask.ymin; + dy= (v2d->cur.ymax-v2d->cur.ymin)*(dy)/div; + + if(0) { // XXX G.qual & LR_SHIFTKEY) { + if(dx>1.0) dx= 1.0; else if(dx<-1.0) dx= -1.0; + } + + dvec[0]+= dx; + dvec[1]+= dy; + + if(midtog) dvec[proj]= 0.0; + ix= floor(dvec[0]+0.5); + iy= floor(dvec[1]+0.5); + + ts= transmain; + + /* SNAP! use the active Seq */ + // XXX snap = G.qual & LR_CTRLKEY ? 1 : 0; + + if (!snap) { + snapskip = 0; + } else { + int dist; + int snap_ofs= 0; + int snap_dist= snapdist_max; + + /* Get sequence points to snap to the markers */ + + snap_point_num=0; + if (last_seq && (last_seq->flag & SELECT)) { /* active seq bounds */ + if(seq_tx_check_left(last_seq)) + snap_points[snap_point_num++] = seq_tx_get_final_left(last_seq, 0); + if(seq_tx_check_right(last_seq)) + snap_points[snap_point_num++] = seq_tx_get_final_right(last_seq, 0); + + } + if (totstrip > 1) { /* selection bounds */ + int bounds_left = MAXFRAME*2; + int bounds_right = -(MAXFRAME*2); + + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if(seq->flag & SELECT) { + if(seq_tx_check_left(seq)) + bounds_left = MIN2(bounds_left, seq_tx_get_final_left(seq, 0)); + if(seq_tx_check_right(seq)) + bounds_right = MAX2(bounds_right,seq_tx_get_final_right(seq, 0)); + } + } + + /* its possible there were no points to set on either side */ + if (bounds_left != MAXFRAME*2) + snap_points[snap_point_num++] = bounds_left; + if (bounds_right != -(MAXFRAME*2)) + snap_points[snap_point_num++] = bounds_right; + } + + + /* Define so we can snap to other points without hassle */ + +#define TESTSNAP(test_frame)\ + for(j=0; j<snap_point_num; j++) {\ + /* see if this beats the current best snap point */\ + dist = abs(snap_points[j] - test_frame);\ + if (dist < snap_dist) {\ + snap_ofs = test_frame - snap_points[j];\ + snap_dist = dist;\ + }\ + } + + + /* Detect the best marker to snap to! */ + for(a=0, marker= scene->markers.first; marker; a++, marker= marker->next) { + + /* dont snap to a marker on the wrong extend side */ + if (mode=='e' && ((side == 'L' && marker->frame > cfra) || (side == 'R' && marker->frame < cfra))) + continue; + + /* when we are moving markers, dont snap to selected markers, durr */ + if ((sseq->flag & SEQ_MARKER_TRANS)==0 || (marker->flag & SELECT)==0) { + + /* loop over the sticky points - max 4 */ + TESTSNAP(marker->frame); + if (snap_dist == 0) break; /* alredy snapped? - stop looking */ + } + } + + if (snap_dist) { + TESTSNAP(cfra); + } + + /* check seq's next to the active also - nice for quick snapping */ + if (snap_dist && last_seq && seq_tx_check_left(last_seq)) { + seq = find_next_prev_sequence(scene, last_seq, 1, 0); /* left */ + if(seq && !seq_tx_check_right(seq)) + TESTSNAP(seq_tx_get_final_right(seq, 0)); + } + + if (snap_dist && last_seq && seq_tx_check_right(last_seq)) { + seq = find_next_prev_sequence(scene, last_seq, 2, 0); /* right */ + if(seq && !seq_tx_check_left(seq)) + TESTSNAP(seq_tx_get_final_left(seq, 0)); + } + +#undef TESTSNAP + + if (abs(ix_old-ix) >= snapdist_max) { + /* mouse has moved out of snap range */ + snapskip = 0; + } else if (snap_dist==0) { + /* nowhere to move, dont do anything */ + snapskip = 1; + } else if (snap_dist < snapdist_max) { + /* do the snapping by adjusting the mouse offset value */ + ix = ix_old + snap_ofs; + } + } + + if (mode=='g' && !snapskip) { + /* Grab */ + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if(seq->flag & SELECT && !(seq->depth==0 && seq->flag & SEQ_LOCK)) { + int myofs; + /* flag, ignores lefsel/rightsel for nested strips */ + int sel_flag = (seq->depth==0) ? seq->flag : seq->flag & ~(SEQ_LEFTSEL+SEQ_RIGHTSEL); + + // SEQ_DEBUG_INFO(seq); + + /* X Transformation */ + if((seq->depth==0) && (sel_flag & SEQ_LEFTSEL)) { + myofs = (ts->startofs - ts->startstill); + seq_tx_set_final_left(seq, ts->start + (myofs + ix)); + } + if((seq->depth==0) && (sel_flag & SEQ_RIGHTSEL)) { + myofs = (ts->endstill - ts->endofs); + seq_tx_set_final_right(seq, ts->start + seq->len + (myofs + ix)); + } + transform_grab_xlimits(seq, sel_flag & SEQ_LEFTSEL, sel_flag & SEQ_RIGHTSEL); + + if( (sel_flag & (SEQ_LEFTSEL+SEQ_RIGHTSEL))==0 ) { + if(sequence_is_free_transformable(seq)) seq->start= ts->start+ ix; + + /* Y Transformation */ + if(seq->depth==0) seq->machine= ts->machine+ iy; + + if(seq->machine<1) seq->machine= 1; + else if(seq->machine>= MAXSEQ) seq->machine= MAXSEQ; + } + calc_sequence(seq); + ts++; + } + } + + /* Markers */ + if (sseq->flag & SEQ_MARKER_TRANS) { + for(a=0, marker= scene->markers.first; marker; marker= marker->next) { + if(marker->flag & SELECT) { + marker->frame= oldframe[a] + ix; + marker_moved=1; + a++; + } + } + } + + /* Extend, grabs one side of the current frame */ + } else if (mode=='e' && !snapskip) { + int myofs; /* offset from start of the seq clip */ + int xnew, final_left, final_right; /* just to store results from seq_tx_get_final_left/right */ + + /* we dont use seq side selection flags for this, + instead we need to calculate which sides to move + based on its initial position from the cursor */ + int move_left, move_right; + + /* Extend, Similar to grab but operate on one side of the cursor */ + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if(seq->flag & SELECT && !(seq->depth==0 && seq->flag & SEQ_LOCK)) { + /* only move the contents of the metastrip otherwise the transformation is applied twice */ + if (sequence_is_free_transformable(seq) && seq->type != SEQ_META) { + + move_left = move_right = 0; + + //SEQ_DEBUG_INFO(seq); + + final_left = seq_tx_get_final_left(seq, 1); + final_right = seq_tx_get_final_right(seq, 1); + + /* Only X Axis moving */ + + /* work out which sides to move first */ + if (side=='L') { + if (final_left <= cfra || ts->final_left <= cfra) move_left = 1; + if (final_right <= cfra || ts->final_right <= cfra) move_right = 1; + } else { + if (final_left >= cfra || ts->final_left >= cfra) move_left = 1; + if (final_right >= cfra || ts->final_right >= cfra) move_right = 1; + } + + if (move_left && move_right) { + /* simple move - dont need to do anything complicated */ + seq->start= ts->start+ ix; + } else { + if (side=='L') { + if (move_left) { + + /* Similar to other funcs */ + myofs = (ts->startofs - ts->startstill); + xnew = ts->start + (ix + myofs); + + /* make sure the we dont resize down to 0 or less in size + also include the startstill so the contense dosnt go outside the bounds, + if the seq->startofs is 0 then its ignored */ + + /* TODO remove, add check to transform_grab_xlimits, works ok for now */ + if (xnew + seq->startstill > final_right-1) { + xnew = (final_right-1) - seq->startstill; + } + /* Note, this is the only case where the start needs to be adjusted + since its not needed when modifying the end or when moving the entire sequence */ + //seq->start = ts->start+ix; // This works when xnew is not clamped, line below takes clamping into account + seq->start= xnew - myofs; /* TODO see above */ + /* done with unique stuff */ + + seq_tx_set_final_left(seq, xnew); + transform_grab_xlimits(seq, 1, 0); + + /* Special case again - setting the end back to what it was */ + seq_tx_set_final_right(seq, final_right); + } + if (move_right) { + myofs = (ts->endstill - ts->endofs); + xnew = ts->start + seq->len + (myofs + ix); + seq_tx_set_final_right(seq, xnew); + transform_grab_xlimits(seq, 0, 1); + } + } else { /* R */ + if (move_left) { + myofs = (ts->startofs - ts->startstill); + xnew = ts->start + (myofs + ix); + seq_tx_set_final_left(seq, xnew); + transform_grab_xlimits(seq, 1, 0); + } + if (move_right) { + myofs = (ts->endstill - ts->endofs); + xnew = ts->start + seq->len + (myofs + ix); + seq_tx_set_final_right(seq, xnew); + transform_grab_xlimits(seq, 0, 1); + } + } + } + } + calc_sequence(seq); + ts++; + } + } + + /* markers */ + if (sseq->flag & SEQ_MARKER_TRANS) { + for(a=0, marker= scene->markers.first; marker; marker= marker->next) {\ + if (marker->flag & SELECT) { + if(oldframe[a] != MAXFRAME+1) { + marker->frame= oldframe[a] + ix; + marker_moved=1; + } + a++; + } + } + } + } + + sprintf(str, "X: %d Y: %d ", ix, iy); +// headerprint(str); + + /* remember the last value for snapping, + only set if we are not currently snapped, + prevents locking on a keyframe */ + if (!snapskip) + ix_old = ix; + + /* just to tell if ctrl was pressed, this means we get a recalc when pressing ctrl */ + snap_old = snap; + + /* rememver last mouse values so we can skip transform when nothing happens */ + xo= mval[0]; + yo= mval[1]; + + /* test for effect and overlap */ + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if((seq->depth==0) && (seq->flag & SELECT) && !(seq->depth==0 && seq->flag & SEQ_LOCK)) { + seq->flag &= ~SEQ_OVERLAP; + if( test_overlap_seq(scene, seq) ) { + seq->flag |= SEQ_OVERLAP; + } + } + 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); + } + } + /* warning, drawing should NEVER use WHILE_SEQ, + if it does the seq->depth value will be messed up and + overlap checks with metastrips will give incorrect results */ +// XXX force_draw_plus(SPACE_BUTS, 0); + + } + +#if 0 + while(qtest()) { + event= extern_qread(&val); + if(val) { + switch(event) { + case ESCKEY: + case LEFTMOUSE: + case RIGHTMOUSE: + case SPACEKEY: + case RETKEY: + afbreek= 1; + break; + case XKEY: + if(!(midtog && (proj == 0))) { + midtog= ~midtog; + } + if(midtog) { + proj= 1; + firsttime= 1; + } + break; + case YKEY: + if(!(midtog && (proj == 1))) { + midtog= ~midtog; + } + if(midtog) { + proj= 0; + firsttime= 1; + } + break; + case MIDDLEMOUSE: + midtog= ~midtog; + if(midtog) { + if( abs(mval[0]-xn) > abs(mval[1]-yn)) proj= 1; + else proj= 0; + firsttime= 1; + } + break; + default: + arrows_move_cursor(event); + } + } + if(afbreek) break; + } +#endif + } + + if((event==ESCKEY) || (event==RIGHTMOUSE)) { + + ts= transmain; + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + if(seq->flag & SELECT && !(seq->depth==0 && seq->flag & SEQ_LOCK)) { + seq->start= ts->start; + seq->machine= ts->machine; + seq->startstill= ts->startstill; + seq->endstill= ts->endstill; + seq->startofs= ts->startofs; + seq->endofs= ts->endofs; + + calc_sequence(seq); + seq->flag &= ~SEQ_OVERLAP; + + ts++; + } 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); + } + } + + /* Markers */ + if (sseq->flag & SEQ_MARKER_TRANS) { + for(a=0, marker= scene->markers.first; marker; marker= marker->next) { + if (marker->flag & SELECT) { + if(oldframe[a] != MAXFRAME+1) { + marker->frame= oldframe[a]; + } + a++; + } + } + marker_moved = 0; + } + } else { + + /* images, effects and overlap */ + for(seq_index=0, seq=seqar[0]; seq_index < totseq_index; seq=seqar[++seq_index]) { + + /* fixes single image strips - makes sure their start is not out of bounds + ideally this would be done during transform since data is rendered at that time + however it ends up being a lot messier! - Campbell */ + fix_single_image_seq(seq); + + if(seq->type == SEQ_META) { + calc_sequence(seq); + seq->flag &= ~SEQ_OVERLAP; + if( test_overlap_seq(scene, seq) ) shuffle_seq(scene, seq); + } + else if(seq->flag & SELECT) { + calc_sequence(seq); + seq->flag &= ~SEQ_OVERLAP; + if( test_overlap_seq(scene, seq) ) shuffle_seq(scene, seq); + } + else if(seq->type & SEQ_EFFECT) calc_sequence(seq); + } + + /* as last: */ + sort_seq(scene); + } + + /* free sequence array */ + if(seqar) MEM_freeN(seqar); + + G.moving= 0; + MEM_freeN(transmain); + + if (sseq->flag & SEQ_MARKER_TRANS && totmark) + MEM_freeN(oldframe); + + if (mode=='g') + BIF_undo_push("Transform Grab, Sequencer"); + else if (mode=='e') + BIF_undo_push("Transform Extend, Sequencer"); + +} + +/* since grab can move markers, we must turn this off before adding a new sequence + I am not so happy with this, but the baddness in contained here - Campbell */ + +/* XXX temp disabled, will work differently anyway */ +void _transform_seq_nomarker_(Scene *scene, SpaceSeq *sseq, View2D *v2d, int mode, int context) +{ + int flag_back; + if (!sseq) return; /* should never happen */ + + flag_back = sseq->flag; + sseq->flag &= ~SEQ_MARKER_TRANS; + + transform_seq(scene, sseq, v2d, mode, context); + + sseq->flag = flag_back; +} + +void seq_separate_images(Scene *scene) +{ + Editing *ed; + 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; + + ed= scene->ed; + if(ed==NULL) return; + + 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(((Editing *)scene->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 (test_overlap_seq(scene, seq_new)) { + shuffle_seq(scene, seq_new); + } + + cfra++; + start_ofs += step; + } + + seq_free_sequence(seq); + seq = seq->next; + } else { + seq = seq->next; + } + } + + /* as last: */ + sort_seq(scene); + BIF_undo_push("Separate Image Strips, Sequencer"); +} + +/* run recursivly to select linked */ +static int select_more_less_seq__internal(Scene *scene, int sel, int linked) { + Editing *ed; + Sequence *seq, *neighbor; + int change=0; + int isel; + + ed= scene->ed; + 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, 1, 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, 2, 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; +} + +void select_less_seq(Scene *scene) +{ + if (select_more_less_seq__internal(scene, 0, 0)) { + BIF_undo_push("Select Less, Sequencer"); + } +} + +void select_more_seq(Scene *scene) +{ + if (select_more_less_seq__internal(scene, 1, 0)) { + BIF_undo_push("Select More, Sequencer"); + } +} + +/* TODO not all modes supported - if you feel like being picky, add them! ;) */ +void select_linked_seq(Scene *scene, View2D *v2d, int mode) +{ + Editing *ed; + Sequence *seq, *mouse_seq; + int selected, hand; + + ed= scene->ed; + if(ed==NULL) return; + + /* replace current selection */ + if (mode==0 || mode==2) { + /* this works like UV, not mesh */ + if (mode==0) { + mouse_seq= find_nearest_seq(scene, v2d, &hand); + if (!mouse_seq) + return; /* user error as with mesh?? */ + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + seq->flag &= ~SELECT; + } + mouse_seq->flag |= SELECT; + recurs_sel_seq(mouse_seq); + } + + selected = 1; + while (selected) { + selected = select_more_less_seq__internal(scene, 1, 1); + } + BIF_undo_push("Select Linked, Sequencer"); + } + /* TODO - more modes... */ +} + +void seq_snap(Scene *scene, short event) +{ + Editing *ed; + Sequence *seq; + + ed= scene->ed; + 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) && + sequence_is_free_transformable(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); + } + transform_grab_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( test_overlap_seq(scene, seq) ) { + shuffle_seq(scene, 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); + + BIF_undo_push("Snap Strips, Sequencer"); +} + +void seq_snap_menu(Scene *scene) +{ + short event; + + event= pupmenu("Snap %t|To Current Frame%x1"); + if(event < 1) return; + + seq_snap(scene, event); +} + + +void seq_mute_sel(Scene *scene, int mute) { + Editing *ed; + Sequence *seq; + + ed= scene->ed; + if(!ed) return; + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + if ((seq->flag & SEQ_LOCK)==0) { + if (mute==-1) { /* hide unselected */ + if ((seq->flag & SELECT)==0) { + seq->flag |= SEQ_MUTE; + } + } else if (seq->flag & SELECT) { + if (mute) seq->flag |= SEQ_MUTE; + else seq->flag &= ~SEQ_MUTE; + } + } + } + BIF_undo_push(mute?"Mute Strips, Sequencer":"UnMute Strips, Sequencer"); +} + +void seq_lock_sel(Scene *scene, int lock) +{ + Editing *ed; + Sequence *seq; + + ed= scene->ed; + if(!ed) return; + + for(seq= ed->seqbasep->first; seq; seq= seq->next) { + if ((seq->flag & SELECT)) { + if (lock) seq->flag |= SEQ_LOCK; + else seq->flag &= ~SEQ_LOCK; + } + } + BIF_undo_push(lock?"Lock Strips, Sequencer":"Unlock Strips, Sequencer"); +} + +void borderselect_seq(Scene *scene, View2D *v2d) +{ + Sequence *seq; + Editing *ed; + rcti rect; + rctf rectf, rq; + int val; + short mval[2]; + + ed= scene->ed; + if(ed==NULL) return; + +// XXX val= get_border(&rect, 3); + + if(val) { + 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); + + seq= ed->seqbasep->first; + while(seq) { + + if(seq->startstill) rq.xmin= seq->start; + else rq.xmin= seq->startdisp; + rq.ymin= seq->machine+0.2; + if(seq->endstill) rq.xmax= seq->start+seq->len; + else rq.xmax= seq->enddisp; + rq.ymax= seq->machine+0.8; + + if(BLI_isect_rctf(&rq, &rectf, 0)) { + if(val==LEFTMOUSE) { + seq->flag |= SELECT; + } + else { + seq->flag &= ~SELECT; + } + recurs_sel_seq(seq); + } + + seq= seq->next; + } + + BIF_undo_push("Border Select, Sequencer"); + } +} |