added keyframe reticle, fixes: DEL, transition at endtrk, DVD/BD render menu
[goodguy/history.git] / cinelerra-5.1 / cinelerra / trackcanvas.C
index 28f149f351ff84f7830e8ed2035e975aa59f5800..e9511d2ded9d2ce2bd8db076495483394eb0a384 100644 (file)
@@ -204,14 +204,24 @@ int TrackCanvas::drag_motion(Track **over_track,
                                        int64_t edit_x, edit_y, edit_w, edit_h;
                                        edit_dimensions(edit, edit_x, edit_y, edit_w, edit_h);
 
-                                       if(cursor_x >= edit_x &&
-                                               cursor_y >= edit_y &&
-                                               cursor_x < edit_x + edit_w &&
-                                               cursor_y < edit_y + edit_h)
-                                       {
+                                       if( cursor_x >= edit_x && cursor_x < edit_x + edit_w &&
+                                           cursor_y >= edit_y && cursor_y < edit_y + edit_h ) {
                                                *over_edit = edit;
                                                break;
                                        }
+                                       if( edit != track->edits->last ) continue;
+                                       if( edit->silence() ) continue;
+                                       if( mwindow->session->current_operation != DRAG_ATRANSITION &&
+                                           mwindow->session->current_operation != DRAG_VTRANSITION ) continue;
+                                       if( cursor_x >= edit_x + edit_w &&
+                                           cursor_y >= edit_y && cursor_y < edit_y + edit_h ) {
+                                               // add silence to allow drag transition past last edit
+                                               //  will be deleted by Edits::optimize if not used
+                                               double length = mwindow->edl->session->default_transition_length;
+                                               int64_t start = edit->startproject+edit->length;
+                                               int64_t units = track->to_units(length, 1); 
+                                               track->edits->create_silence(start, start+units);
+                                       }
                                }
 
                                for(int i = 0; i < track->plugin_set.total; i++)
@@ -2014,7 +2024,7 @@ int TrackCanvas::do_keyframes(int cursor_x,
                                        {
                                                if (buttonpress != 3)
                                                {
-                                                       if(i == AUTOMATION_FADE)
+                                                       if(i == AUTOMATION_FADE || i == AUTOMATION_SPEED)
                                                                synchronize_autos(0,
                                                                        track,
                                                                        (FloatAuto*)mwindow->session->drag_auto,
@@ -2031,6 +2041,12 @@ int TrackCanvas::do_keyframes(int cursor_x,
                                                        gui->keyframe_menu->activate_menu();
                                                        rerender = 1; // the position changes
                                                }
+                                               else if( autos )
+                                               {
+                                                       gui->keyframe_hide->update(autos);
+                                                       gui->keyframe_hide->activate_menu();
+                                                       rerender = 1; // the position changes
+                                               }
                                                if(buttonpress == 1 && ctrl_down() &&
                                                   AUTOMATION_TYPE_FLOAT == autos->get_type())
                                                        rerender = 1; // special case: curve mode changed
@@ -2085,6 +2101,45 @@ int TrackCanvas::do_keyframes(int cursor_x,
        return result;
 }
 
+void TrackCanvas::draw_keyframe_reticle()
+{
+       int keyframe_hairline = mwindow->preferences->keyframe_reticle;
+       if( keyframe_hairline == HAIRLINE_NEVER ) return;
+
+       int current_op = mwindow->session->current_operation, dragging = 0;
+       for( int i=0; !dragging && i<AUTOMATION_TOTAL; ++i )
+               if( current_op == auto_operations[i] ) dragging = 1;
+
+       if( keyframe_hairline == HAIRLINE_DRAGGING && dragging ) {
+               if( mwindow->session->drag_auto && get_buttonpress() == 1 ) {
+                       draw_hairline(mwindow->session->drag_auto, RED);
+                       return;
+               }
+       }
+
+       if( keyframe_hairline == HAIRLINE_ALWAYS || ( get_buttonpress() == 2 &&
+           keyframe_hairline == HAIRLINE_DRAGGING && dragging ) ) {
+               for( Track *track = mwindow->edl->tracks->first; track;
+                    track=track->next ) {
+                       Automation *automation = track->automation;
+                       for( int i=0; i<AUTOMATION_TOTAL; ++i ) {
+                               if( !mwindow->edl->session->auto_conf->autos[i] ) continue;
+                               // automation visible
+                               Autos *autos = automation->autos[i];
+                               if( !autos ) continue;
+                               for( Auto *auto_keyframe=autos->first; auto_keyframe;
+                                    auto_keyframe = auto_keyframe->next ) {
+                                       draw_hairline(auto_keyframe, GREEN);
+                               }
+                       }
+
+                       if( dragging && mwindow->session->drag_auto ) {
+                               draw_hairline(mwindow->session->drag_auto, RED);
+                       }
+               }
+       }
+}
+
 void TrackCanvas::draw_auto(Auto *current,
        int x,
        int y,
@@ -2311,8 +2366,7 @@ float levered_position(float position, float ref_pos)
 {
        if( 1e-6 > fabs(ref_pos) || isnan(ref_pos)) 
                return 0.0;
-       else 
-               return ref_pos / position;
+       return ref_pos / position;
 }
 
 
@@ -2324,10 +2378,9 @@ float TrackCanvas::value_to_percentage(float auto_value, int autogrouptype)
        float automation_min = mwindow->edl->local_session->automation_mins[autogrouptype];
        float automation_max = mwindow->edl->local_session->automation_maxs[autogrouptype];
        float automation_range = automation_max - automation_min;
-       if(0 == automation_range || isnan(auto_value) || isinf(auto_value))
+       if( 0 >= automation_range || isnan(auto_value) || isinf(auto_value) )
                return 0;
-       else
-               return (auto_value - automation_min) / automation_range;
+       return (auto_value - automation_min) / automation_range;
 }
 
 
@@ -2508,7 +2561,7 @@ void TrackCanvas::draw_floatline(int center_pixel,
 
 // Not using slope intercept
        x1 = MAX(0, x1);
-       int prev_y = y1;
+       int prev_y = y1 + center_pixel;
 
 
 // Call by reference fails for some reason here
@@ -2531,6 +2584,7 @@ void TrackCanvas::draw_floatline(int center_pixel,
 // (int)(center_pixel - yscale / 2),
 // (int)(center_pixel + yscale / 2 - 1));
 
+//printf("draw_line(%d,%d,  %d,%d)\n", x - 1, prev_y  , x, y);
                        draw_line(x - 1, prev_y  , x, y   );
                }
                prev_y = y;
@@ -2596,71 +2650,62 @@ int TrackCanvas::test_floatline(int center_pixel,
 
 
 void TrackCanvas::synchronize_autos(float change,
-       Track *skip,
-       FloatAuto *fauto,
-       int fill_gangs)
+               Track *skip, FloatAuto *fauto, int fill_gangs)
 {
 // Handles the special case of modifying a fadeauto
 // when there are ganged faders on several tracks
 // (skip and fauto may be NULL if fill_gangs==-1)
-       if (fill_gangs == 1 && skip->gang)
-       {
-               for(Track *current = mwindow->edl->tracks->first;
-                       current;
-                       current = NEXT)
-               {
-                       if(current->data_type == skip->data_type &&
-                               current->gang &&
-                               current->record &&
-                               current != skip)
-                       {
-                               FloatAutos *fade_autos = (FloatAutos*)current->automation->autos[AUTOMATION_FADE];
-                               double position = skip->from_units(fauto->position);
-                               FloatAuto *previous = 0, *next = 0;
 
-                               float init_value = fade_autos->get_value(fauto->position, PLAY_FORWARD, previous, next);
-                               FloatAuto *keyframe;
-                               keyframe = (FloatAuto*)fade_autos->get_auto_at_position(position);
-
-                               if (!keyframe)
-                               {
+       if( fill_gangs > 0 && skip->gang ) {
+               double position = skip->from_units(fauto->position);
+               int autoidx = fauto->autos->autoidx;
+
+               for(Track *current = mwindow->edl->tracks->first; current; current = NEXT) {
+                       if( (current->data_type == skip->data_type || get_double_click()) &&
+                           current->gang && current->record && current != skip ) {
+                               int64_t current_position = current->to_units(position, 1);
+                               FloatAutos *fade_autos = (FloatAutos*)current->automation->autos[autoidx];
+                               float auto_min = mwindow->edl->local_session->automation_mins[fade_autos->autogrouptype];
+                               float auto_max = mwindow->edl->local_session->automation_maxs[fade_autos->autogrouptype];
+                               FloatAuto *previous = 0, *next = 0;
+                               FloatAuto *keyframe = (FloatAuto*)fade_autos->get_auto_at_position(current_position);
+                               if( !keyframe ) {
 // create keyframe on neighbouring track at the point in time given by fauto
-                                       keyframe = (FloatAuto*)fade_autos->insert_auto(fauto->position);
-                                       keyframe->set_value(init_value + change);
+                                       float init_value = fade_autos->get_value(current_position, PLAY_FORWARD, previous, next);
+                                       float new_value = init_value + change;
+                                       CLAMP(new_value, auto_min, auto_max);
+                                       keyframe = (FloatAuto*)fade_autos->insert_auto(current_position);
+                                       keyframe->set_value(new_value);
                                }
-                               else
-                               {
+                               else {
 // keyframe exists, just change it
-                                       keyframe->adjust_to_new_coordinates(fauto->position, keyframe->get_value() + change);
+                                       float new_value = keyframe->get_value() + change;
+                                       CLAMP(new_value, auto_min, auto_max);
+                                       keyframe->adjust_to_new_coordinates(current_position, new_value);
 // need to (re)set the position, as the existing node could be on a "equivalent" position (within half a frame)
                                }
 
                                mwindow->session->drag_auto_gang->append((Auto *)keyframe);
                        }
                }
-       } else
-// move the gangs
-       if (fill_gangs == 0)
-       {
-// Move the gang!
-               for (int i = 0; i < mwindow->session->drag_auto_gang->total; i++)
-               {
+       }
+       else if( !fill_gangs ) {
+               double position = skip->from_units(fauto->position);
+// Move the gangs
+               for (int i = 0; i < mwindow->session->drag_auto_gang->total; i++) {
                        FloatAuto *keyframe = (FloatAuto *)mwindow->session->drag_auto_gang->values[i];
-
+                       int64_t keyframe_position = keyframe->autos->track->to_units(position, 1);
                        float new_value = keyframe->get_value() + change;
                        CLAMP(new_value,
                              mwindow->edl->local_session->automation_mins[keyframe->autos->autogrouptype],
                              mwindow->edl->local_session->automation_maxs[keyframe->autos->autogrouptype]);
-                       keyframe->adjust_to_new_coordinates(fauto->position, new_value);
+                       keyframe->adjust_to_new_coordinates(keyframe_position, new_value);
                }
 
        }
-       else
+       else {
 // remove the gangs
-       if (fill_gangs == -1)
-       {
-               for (int i = 0; i < mwindow->session->drag_auto_gang->total; i++)
-               {
+               for (int i = 0; i < mwindow->session->drag_auto_gang->total; i++) {
                        FloatAuto *keyframe = (FloatAuto *)mwindow->session->drag_auto_gang->values[i];
                        keyframe->autos->remove_nonsequential(
                                        keyframe);
@@ -2864,10 +2909,10 @@ int TrackCanvas::do_float_autos(Track *track, Autos *autos, int cursor_x, int cu
                 autos->first ? autos->first : autos->default_auto;
 
        double ax = 0, ay = 0, ax2 = 0, ay2 = 0;
-       if( first_auto )
+       if( first_auto ) {
                calculate_auto_position(&ax, &ay, 0, 0, 0, 0,
                        first_auto, unit_start, zoom_units, yscale, autogrouptype);
-
+       }
        if( current )
                current = NEXT;
        else {
@@ -3332,6 +3377,28 @@ int TrackCanvas::do_plugin_autos(Track *track, int cursor_x, int cursor_y,
        return result;
 }
 
+int TrackCanvas::draw_hairline(Auto *auto_keyframe, int color)
+{
+       Track *track = auto_keyframe->autos->track;
+       int autogrouptype = auto_keyframe->autos->get_type();
+
+       int center_pixel;
+       double view_start, unit_start;
+       double view_end, unit_end, yscale;
+       double zoom_sample, zoom_units;
+
+       calculate_viewport(track, view_start, unit_start, view_end, unit_end,
+                       yscale, center_pixel, zoom_sample, zoom_units);
+
+       double ax = 0, ay = 0;
+       calculate_auto_position(&ax, &ay, 0, 0, 0, 0,
+               auto_keyframe, unit_start, zoom_units, yscale, autogrouptype);
+
+       set_color(color);
+       draw_line(ax, 0, ax, get_h());
+       return 0;
+}
+
 void TrackCanvas::draw_overlays()
 {
        int new_cursor, update_cursor, rerender;
@@ -3373,6 +3440,8 @@ void TrackCanvas::draw_overlays()
 // Playback cursor
        draw_playback_cursor();
 
+       draw_keyframe_reticle();
+
        show_window(0);
 }
 
@@ -3485,36 +3554,22 @@ int TrackCanvas::get_drag_values(float *percentage,
 
 
 #define UPDATE_DRAG_HEAD(do_clamp) \
-       int result = 0; \
+       int result = 0, center_pixel; \
        if(!current->autos->track->record) return 0; \
-       double view_start; \
-       double unit_start; \
-       double view_end; \
-       double unit_end; \
-       double yscale; \
-       int center_pixel; \
-       double zoom_sample; \
-       double zoom_units; \
+       double view_start, unit_start, view_end, unit_end; \
+       double yscale, zoom_sample, zoom_units; \
  \
        calculate_viewport(current->autos->track,  \
-               view_start, \
-               unit_start, \
-               view_end, \
-               unit_end, \
-               yscale, \
-               center_pixel, \
-               zoom_sample, \
-               zoom_units); \
+               view_start, unit_start, view_end, unit_end, \
+               yscale, center_pixel, zoom_sample, zoom_units); \
  \
        float percentage = (float)(mwindow->session->drag_origin_y - cursor_y) / \
-               yscale +  \
-               mwindow->session->drag_start_percentage; \
+               yscale +  mwindow->session->drag_start_percentage; \
        if(do_clamp) CLAMP(percentage, 0, 1); \
  \
        int64_t position = Units::to_int64(zoom_units * \
                (cursor_x - mwindow->session->drag_origin_x) + \
                mwindow->session->drag_start_position); \
- \
        if((do_clamp) && position < 0) position = 0;
 
 
@@ -3523,119 +3578,99 @@ int TrackCanvas::update_drag_floatauto(int cursor_x, int cursor_y)
        FloatAuto *current = (FloatAuto*)mwindow->session->drag_auto;
 
        UPDATE_DRAG_HEAD(mwindow->session->drag_handle == 0);
-       int x = cursor_x - mwindow->session->drag_origin_x; \
-       int y = cursor_y - mwindow->session->drag_origin_y; \
-
-       float value;
-       float old_value;
+       int x = cursor_x - mwindow->session->drag_origin_x;
+       int y = cursor_y - mwindow->session->drag_origin_y;
+       float value, old_value;
+
+       if( mwindow->session->drag_handle == 0 && (ctrl_down() && !shift_down()) ) {
+// not really editing the node, rather start editing the curve
+// tangent is editable and drag movement is significant
+               if( (FloatAuto::FREE == current->curve_mode ||
+                    FloatAuto::TFREE==current->curve_mode) &&                                          
+                   (fabs(x) > HANDLE_W / 2 || fabs(y) > HANDLE_W / 2))
+                       mwindow->session->drag_handle = x < 0 ? 1 : 2;
+       }
 
-       switch(mwindow->session->drag_handle)
-       {
-// Center
-               case 0:
-                       if(ctrl_down())
-                       // not really editing the node, rather start editing the curve
-                       {
-                               // tangent is editable and drag movement is significant
-                               if( (FloatAuto::FREE == current->curve_mode ||
-                                    FloatAuto::TFREE==current->curve_mode) &&                                          
-                                   (fabs(x) > HANDLE_W / 2 || fabs(y) > HANDLE_W / 2))
-                                       mwindow->session->drag_handle = x < 0 ? 1 : 2;
-                               break;
-                       }
+       switch(mwindow->session->drag_handle) {
+       case 0: // Center
 // Snap to nearby values
-                       old_value = current->get_value();
-                       if(shift_down())
-                       {
-                               double value1;
-                               double distance1;
-                               double value2;
-                               double distance2;
+               old_value = current->get_value();
+               if(shift_down()) {
+                       double value1, value2, distance1, distance2;
 
-                               if(current->previous)
-                               {
-                                       int autogrouptype = current->previous->autos->autogrouptype;
-                                       value = percentage_to_value(percentage, 0, 0, autogrouptype);
-                                       value1 = ((FloatAuto*)current->previous)->get_value();
-                                       distance1 = fabs(value - value1);
-                                       current->set_value(value1);
-                               }
-
-                               if(current->next)
-                               {
-                                       int autogrouptype = current->next->autos->autogrouptype;
-                                       value = percentage_to_value(percentage, 0, 0, autogrouptype);
-                                       value2 = ((FloatAuto*)current->next)->get_value();
-                                       distance2 = fabs(value - value2);
-                                       if(!current->previous || distance2 < distance1)
-                                       {
-                                               current->set_value(value2);
-                                       }
-                               }
+                       if(current->previous) {
+                               int autogrouptype = current->previous->autos->autogrouptype;
+                               value = percentage_to_value(percentage, 0, 0, autogrouptype);
+                               value1 = ((FloatAuto*)current->previous)->get_value();
+                               distance1 = fabs(value - value1);
+                               current->set_value(value1);
+                       }
 
-                               if(!current->previous && !current->next)
-                               {
-                                       current->set_value( ((FloatAutos*)current->autos)->default_);
+                       if(current->next) {
+                               int autogrouptype = current->next->autos->autogrouptype;
+                               value = percentage_to_value(percentage, 0, 0, autogrouptype);
+                               value2 = ((FloatAuto*)current->next)->get_value();
+                               distance2 = fabs(value - value2);
+                               if(!current->previous || distance2 < distance1) {
+                                       current->set_value(value2);
                                }
-                               value = current->get_value();
                        }
-                       else
-                       {
-                               int autogrouptype = current->autos->autogrouptype;
-                               value = percentage_to_value(percentage, 0, 0, autogrouptype);
+
+                       if(!current->previous && !current->next) {
+                               current->set_value( ((FloatAutos*)current->autos)->default_);
                        }
+                       value = current->get_value();
+               }
+               else {
+                       int autogrouptype = current->autos->autogrouptype;
+                       value = percentage_to_value(percentage, 0, 0, autogrouptype);
+               }
 
-                       if(alt_down())
+               if(alt_down() && !shift_down())
 // ALT constrains movement: fixed position, only changing the value
-                               position = mwindow->session->drag_start_position;
+                       position = mwindow->session->drag_start_position;
 
-                       if(value != old_value || position != current->position)
-                       {
-                               result = 1;
-                               float change = value - old_value;               
-                               current->adjust_to_new_coordinates(position, value);
-                               synchronize_autos(change, current->autos->track, current, 0);
-                               show_message(current, 1,", %.2f", current->get_value());
-                       }
-                       break;
+               if(value != old_value || position != current->position) {
+                       result = 1;
+                       float change = value - old_value;               
+                       current->adjust_to_new_coordinates(position, value);
+                       synchronize_autos(change, current->autos->track, current, 0);
+                       show_message(current, 1,", %.2f", current->get_value());
+               }
+               break;
 
 // In control
-               case 1:
+       case 1: {
+               int autogrouptype = current->autos->autogrouptype;
+               value = percentage_to_value(percentage, 0, current, autogrouptype);
+               if(value != current->get_control_in_value())
                {
-                       int autogrouptype = current->autos->autogrouptype;
-                       value = percentage_to_value(percentage, 0, current, autogrouptype);
-                       if(value != current->get_control_in_value())
-                       {
-                               result = 1;
-                               // note: (position,value) need not be at the location of the ctrl point,
-                               // but could be somewhere in between on the curve (or even outward or
-                               // on the opposit side). We set the new control point such as
-                               // to point the curve through (position,value)
-                               current->set_control_in_value(
-                                       value * levered_position(position - current->position,
-                                                                current->get_control_in_position()));
-                               synchronize_autos(0, current->autos->track, current, 0);
-                               show_message(current, 1,", %.2f", current->get_control_in_value());
-                       }
+                       result = 1;
+                       // note: (position,value) need not be at the location of the ctrl point,
+                       // but could be somewhere in between on the curve (or even outward or
+                       // on the opposit side). We set the new control point such as
+                       // to point the curve through (position,value)
+                       current->set_control_in_value(
+                               value * levered_position(position - current->position,
+                                                        current->get_control_in_position()));
+                       synchronize_autos(0, current->autos->track, current, 0);
+                       show_message(current, 1,", %.2f", current->get_control_in_value());
                }
-                       break;
+               break; }
 
 // Out control
-               case 2:
-               {
-                       int autogrouptype = current->autos->autogrouptype;
-                       value = percentage_to_value(percentage, 0, current, autogrouptype);
-                       if(value != current->get_control_out_value())
-                       {
-                               result = 1;
-                               current->set_control_out_value(
-                                       value * levered_position(position - current->position,
-                                                                current->get_control_out_position()));
-                               synchronize_autos(0, current->autos->track, current, 0);
-                               show_message(current, 1,", %.2f", current->get_control_out_value());
-                       }
+       case 2: {
+               int autogrouptype = current->autos->autogrouptype;
+               value = percentage_to_value(percentage, 0, current, autogrouptype);
+               if(value != current->get_control_out_value()) {
+                       result = 1;
+                       current->set_control_out_value(
+                               value * levered_position(position - current->position,
+                                                        current->get_control_out_position()));
+                       synchronize_autos(0, current->autos->track, current, 0);
+                       show_message(current, 1,", %.2f", current->get_control_out_value());
                }
-                       break;
+               break; }
        }
 
        return result;