reload plugin btn in prefs, speed gang fader tweaks
[goodguy/history.git] / cinelerra-5.1 / cinelerra / trackcanvas.C
index 2e21511e31aad2d68ac5bf6d1908607259c78b21..fdd3112bb6b2fb62f315fc7c2f3fb70de94bf9ba 100644 (file)
@@ -26,7 +26,9 @@
 #include "bcsignals.h"
 #include "bctimer.h"
 #include "clip.h"
-#include "colors.h"
+#include "bccolors.h"
+#include "cache.h"
+#include "canvas.h"
 #include "cplayback.h"
 #include "cursors.h"
 #include "cwindowgui.h"
@@ -46,6 +48,7 @@
 #include "keyframepopup.h"
 #include "keyframes.h"
 #include "keys.h"
+#include "labels.h"
 #include "localsession.h"
 #include "mainclock.h"
 #include "maincursor.h"
@@ -66,6 +69,7 @@
 #include "pluginset.h"
 #include "plugintoggles.h"
 #include "preferences.h"
+#include "renderengine.h"
 #include "resourcepixmap.h"
 #include "resourcethread.h"
 #include "swindow.h"
@@ -79,6 +83,7 @@
 #include "transportque.h"
 #include "vframe.h"
 #include "vpatchgui.inc"
+#include "vrender.h"
 #include "zoombar.h"
 
 #include <string.h>
@@ -109,6 +114,7 @@ TrackCanvas::TrackCanvas(MWindow *mwindow,
        render_timer = new Timer;
        hourglass_enabled = 0;
        timebar_position = -1;
+       snapped = 0;
 }
 
 TrackCanvas::~TrackCanvas()
@@ -186,7 +192,7 @@ int TrackCanvas::drag_motion(Track **over_track,
        int cursor_y = get_relative_cursor_y();
 
        if( get_cursor_over_window() &&
-               cursor_x >= 0 && cursor_y >= 0 && 
+               cursor_x >= 0 && cursor_y >= 0 &&
                cursor_x < get_w() && cursor_y < get_h() )
        {
 //printf("TrackCanvas::drag_motion %d %d\n", __LINE__, pane->number);
@@ -217,7 +223,7 @@ int TrackCanvas::drag_motion(Track **over_track,
                                                //  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); 
+                                               int64_t units = track->to_units(length, 1);
                                                track->edits->create_silence(start, start+units);
                                                continue;
                                        }
@@ -329,16 +335,28 @@ int TrackCanvas::drag_stop(int *redraw)
                                if( hi_plugin_set && hi_plugin_set->track == drag_plugin->track ) {
 //printf("TrackCanvas::drag_stop 6\n");
                                        drop_position = drop_plugin_position(hi_plugin_set, drag_plugin);
-                                       if( drop_position >= 0 )
-                                               mwindow->move_effect(drag_plugin, hi_plugin_set, drop_position);
+                                       if( drop_position < 0 ) {
+                                               result = 1;
+                                               break;          // Do not do anything
+                                       }
+
+                                       Track *track = mwindow->session->track_highlighted;
+                                       drop_position = track->frame_align(drop_position, 0);
+                                       mwindow->move_effect(drag_plugin, hi_plugin_set, drop_position);
                                        result = 1;
                                }
                                else if( hi_track ) {
 // Put it in a new plugin set determined by an edit boundary, or at the start of the track
                                        Edit *hi_edit = mwindow->session->edit_highlighted;
                                        drop_position = hi_edit ? hi_edit->startproject : 0;
-                                       if( drop_position >= 0 )
-                                               mwindow->move_effect(drag_plugin, hi_track, drop_position);
+                                       if( drop_position < 0 ) {
+                                               result = 1;
+                                               break;          // Do not do anything
+                                       }
+
+                                       Track *track = mwindow->session->track_highlighted;
+                                       drop_position = track->frame_align(drop_position, 0);
+                                       mwindow->move_effect(drag_plugin, hi_track, drop_position);
                                        result = 1;
                                }
                        }
@@ -380,7 +398,7 @@ int TrackCanvas::drag_stop(int *redraw)
                                        length = mwindow->session->track_highlighted->from_units(
                                                mwindow->session->edit_highlighted->length);
                                }
-
+                               start = mwindow->edl->align_to_frame(start, 0);
                                mwindow->insert_effects_canvas(start, length);
                                *redraw = 1;
                        }
@@ -392,8 +410,7 @@ int TrackCanvas::drag_stop(int *redraw)
                        if(mwindow->session->track_highlighted) {
                                double asset_duration = 0;
                                int64_t asset_length_units = 0;
-                               int64_t position = 0;
-                                       
+
                                if(mwindow->session->current_operation == DRAG_ASSET &&
                                        mwindow->session->drag_assets->total) {
                                        Indexable *indexable = mwindow->session->drag_assets->values[0];
@@ -405,8 +422,8 @@ int TrackCanvas::drag_stop(int *redraw)
                                                if (video_length < 0) {
                                                        if(mwindow->edl->session->si_useduration)
                                                                video_length = mwindow->edl->session->si_duration;
-                                                       else    
-                                                               video_length = 1.0 / mwindow->edl->session->frame_rate ; 
+                                                       else
+                                                               video_length = 1.0 / mwindow->edl->session->frame_rate ;
                                                }
                                                asset_duration = video_length / indexable->get_frame_rate();
                                        }
@@ -428,25 +445,26 @@ int TrackCanvas::drag_stop(int *redraw)
                                else {
                                        printf("DRAG_ASSET error: Asset dropped, but both drag_clips and drag_assets total is zero\n");
                                }
-                       
+
                                asset_length_units = mwindow->session->track_highlighted->to_units(asset_duration, 1);
-                               position = drop_edit_position (&insertion, NULL, asset_length_units);
-                               if( position == -1 ) {
+                               int64_t drop_position = drop_edit_position (&insertion, NULL, asset_length_units);
+                               if( drop_position < 0 ) {
                                        result = 1;
                                        break;          // Do not do anything
                                }
-                               
-                               double position_f = mwindow->session->track_highlighted->from_units(position);
+
                                Track *track = mwindow->session->track_highlighted;
+                               double track_position = track->from_units(drop_position);
+                               track_position = mwindow->edl->align_to_frame(track_position, 0);
 
 //                             if (!insertion) {
 //                                     // FIXME, we should create an mwindow/EDL method that overwrites, without clearing the keyframes and autos
 //                                     // Unfortunately, this is _a lot_ of work to do right
 //                                     printf("Problematic insertion\n");
-//                                     mwindow->edl->tracks->clear(position_f, 
-//                                             position_f + asset_duration, 0);
+//                                     mwindow->edl->tracks->clear(track_position,
+//                                             track_position + asset_duration, 0);
 //                             }
-                               mwindow->paste_assets(position_f, track, !insertion);
+                               mwindow->paste_assets(track_position, track, !insertion);
                                result = 1;    // need to be one no matter what, since we have track highlited so we have to cleanup....
                        }
                        break;
@@ -456,19 +474,18 @@ int TrackCanvas::drag_stop(int *redraw)
                        if(mwindow->session->track_highlighted) {
                                if( mwindow->session->track_highlighted->data_type ==
                                        mwindow->session->drag_edit->track->data_type) {
-                                       int64_t position = 0;
-                                       position = drop_edit_position(&insertion,
+                                       int64_t drop_position = drop_edit_position(&insertion,
                                                        mwindow->session->drag_edit,
                                                        mwindow->session->drag_edit->length);
-                                       if (position == -1) {
+                                       if( drop_position < 0 ) {
                                                result = 1;
                                                break;          // Do not do anything
                                        }
-                                       
-                                       double position_f = mwindow->session->track_highlighted->from_units(position);
                                        Track *track = mwindow->session->track_highlighted;
+                                       double track_position = track->from_units(drop_position);
+                                       track_position = mwindow->edl->align_to_frame(track_position, 0);
                                        mwindow->move_edits(mwindow->session->drag_edits,
-                                                       track, position_f, !insertion);
+                                                       track, track_position, !insertion);
                                }
 
                                result = 1;
@@ -509,68 +526,67 @@ int64_t TrackCanvas::drop_edit_position(int *is_insertion, Edit *moved_edit, int
        Track *track = mwindow->session->track_highlighted;
        int cursor_x = get_relative_cursor_x();
        double zoom_scale = (double)mwindow->edl->session->sample_rate / mwindow->edl->local_session->zoom_sample;
-       double drop_time = (cursor_x + mwindow->edl->local_session->view_start[pane->number]) / zoom_scale;
-       // we use cursor position for affinity calculations
-       int64_t cursor_position = track->to_units(drop_time, 0);
-       if( cursor_position <= 0 ) {
+       double cur_pos = (cursor_x + mwindow->edl->local_session->view_start[pane->number]) / zoom_scale;
+       double position = mwindow->edl->align_to_frame(cur_pos, 1);
+       if( position <= 0 ) {
                *is_insertion = 1;
                return 0;
        }
-       if( moved_edit )  // relative cursor position depends upon drop point
-               drop_time -= mwindow->session->drag_position - moved_edit->track->from_units(moved_edit->startproject);
-       int64_t drop_position = track->to_units(drop_time, 1);
+       double cursor_position = position;
+       int64_t drop_position = track->to_units(cursor_position, 1);
+       if( moved_edit ) { // relative cursor position depends upon drop point
+               double moved_edit_start = moved_edit->track->from_units(moved_edit->startproject);
+               position -= mwindow->session->drag_position - moved_edit_start;
+       }
+       int64_t edit_position = track->to_units(position, 1);
+       int64_t grab_position = edit_position;
        if( !moved_edit )  // for clips and assets acts as they were grabbed in the middle
-               drop_position -= moved_edit_length / 2;
+               grab_position -= moved_edit_length / 2;
        Edit *last_edit = track->edits->last;
-       if( !last_edit || drop_position > last_edit->startproject+last_edit->length ) {
+       if( !last_edit || edit_position >= (last_edit->startproject+last_edit->length) ) {
                *is_insertion = 0;
-               return drop_position;
+               return grab_position;
        }
 
-       int64_t drop_x0 = 0, drop_x1 = 0;  // drop zone boundries
-       for( Edit *edit = track->edits->first; edit; ) {
-               int64_t edit_x0 = edit->startproject, edit_x1 = edit_x0 + edit->length;
-               if( Units::round(labs(edit_x0-cursor_position)*zoom_scale) < HANDLE_W ) {
+       int64_t drop_start = 0, drop_end = 0;  // drop zone boundries
+       Edit *next_edit = track->edits->first;
+       while( next_edit ) {
+               Edit *edit = next_edit;  next_edit = (Edit *)edit->next;
+               int64_t edit_start = edit->startproject;
+               int64_t edit_end = edit_start + edit->length;
+               double edit_start_pos = edit->track->from_units(edit_start);
+               if( (fabs(edit_start_pos-cursor_position)*zoom_scale) < HANDLE_W ) {
                        *is_insertion = 1; // cursor is close to the beginning of an edit -> insertion
-                       return edit->startproject;
+                       return edit_start;
                }
-               if( Units::round(labs(edit_x1-cursor_position)*zoom_scale) < HANDLE_W ) {
+               double edit_end_pos = edit->track->from_units(edit_end);
+               if( (fabs(edit_end_pos-cursor_position)*zoom_scale) < HANDLE_W ) {
                        *is_insertion = 1; // cursor is close to the end of an edit -> insertion
-                       return edit->startproject + edit->length;
+                       return edit_end;
                }
                if( edit != moved_edit && !edit->silence() )
-                       drop_x0 = edit_x1; // reset drop zone
-               if( (edit=edit->next) != 0 ) {
-                       if( edit == moved_edit || edit->silence() ) continue;
-                       drop_x1 = edit_x1;
+                       drop_start = edit_end; // reset drop zone
+               if( next_edit ) {
+                       if( next_edit == moved_edit || next_edit->silence() ) continue;
+                       drop_end = edit_end;
                }
                else
-                       drop_x1 = INT64_MAX;
-//printf("drop cursor=%jd, x0=%jd, x1=%jd\n", cursor_position, drop_x0, drop_x1);
-               if( drop_position >= drop_x0 && drop_position+moved_edit_length < drop_x1 ) {
+                       drop_end = INT64_MAX;
+               if( edit_position >= drop_start &&
+                   edit_position+moved_edit_length < drop_end ) {
                        *is_insertion = 0; // fits in the zone
-//printf("into %jd\n", drop_position);
-                       return drop_position;
+                       return edit_position;
                }
-               if( cursor_position < drop_x1 ) { // drop in the zone
-                       if( (drop_x1-drop_x0) >= moved_edit_length ) {
+               if( drop_position < drop_end ) { // drop in the zone
+                       if( (drop_end - drop_start) >= moved_edit_length ) {
                                *is_insertion = 0; // fits in the zone, but over the edge
-                               int64_t dx0 = llabs(cursor_position-drop_x0);
-                               int64_t dx1 = llabs(cursor_position-drop_x1);
-//printf("onto %jd\n", dx0 < dx1 ? drop_x0 : drop_x1 - moved_edit_length);
-                               return dx0 < dx1 ? drop_x0 : drop_x1 - moved_edit_length;
-                       }
-                       int edit_center = (edit_x0+edit_x1) / 2;
-                       if( cursor_position < edit_center ) {
-                               *is_insertion = 1;
-//printf("snap left %jd\n", drop_x0);
-                               return drop_x0; // snap left
-                       }
-                       else {
-                               *is_insertion = 1;
-//printf("snap right %jd\n", drop_x1);
-                               return drop_x1; // snap right
+                               int64_t dx0 = llabs(drop_position - drop_start);
+                               int64_t dx1 = llabs(drop_position - drop_end);
+                               return dx0 < dx1 ? drop_start : drop_end - moved_edit_length;
                        }
+                       *is_insertion = 1;
+                       int64_t edit_center = (edit_start + edit_end) / 2;
+                       return position < edit_center ? drop_start : drop_end;
                }
        }
 
@@ -582,39 +598,47 @@ int64_t TrackCanvas::drop_plugin_position(PluginSet *plugin_set, Plugin *moved_p
 {
        // get the canvas/track position
        Track *track = plugin_set->track;
+       double moved_plugin_length = moved_plugin->track->from_units(moved_plugin->length);
+       int64_t track_plugin_length = track->to_units(moved_plugin_length, 0);
        int cursor_x = get_relative_cursor_x();
        double zoom_scale = (double)mwindow->edl->session->sample_rate / mwindow->edl->local_session->zoom_sample;
-       double drop_time = (cursor_x + mwindow->edl->local_session->view_start[pane->number]) / zoom_scale;
-       // we use cursor position for affinity calculations
-       int64_t cursor_position = track->to_units(drop_time, 0);
-       if( cursor_position <= 0 ) return 0;
-       drop_time -= mwindow->session->drag_position - moved_plugin->track->from_units(moved_plugin->startproject);
-       int64_t drop_position = track->to_units(drop_time, 1);
+       double cur_pos = (cursor_x + mwindow->edl->local_session->view_start[pane->number]) / zoom_scale;
+       double position = mwindow->edl->align_to_frame(cur_pos, 1);
+       if( position <= 0 ) return 0;
+       int64_t drop_position = track->to_units(position, 1);
        Plugin *last_plugin = (Plugin *)plugin_set->last;
-       if( !last_plugin || drop_position > last_plugin->startproject+last_plugin->length ) {
-               return drop_position;
-       }
-
-       int64_t drop_x0 = 0, drop_x1 = 0;  // drop zone boundries
-       for( Plugin *plugin = (Plugin *)plugin_set->first; plugin; ) {
-               int64_t plugin_x0 = plugin->startproject, plugin_x1 = plugin_x0 + plugin->length;
+       if( !last_plugin ) return drop_position;
+       double plugin_set_end = last_plugin->track->from_units(last_plugin->startproject+last_plugin->length);
+       if( position >= plugin_set_end ) return drop_position;
+       double moved_plugin_start = moved_plugin->track->from_units(moved_plugin->startproject);
+       position -= mwindow->session->drag_position - moved_plugin_start;
+       int64_t plugin_position = track->to_units(position, 1);
+
+       int64_t drop_start = 0, drop_end = 0;  // drop zone boundries
+       Plugin *next_plugin = (Plugin *)plugin_set->first;
+       while( next_plugin ) {
+               Plugin *plugin = next_plugin;  next_plugin = (Plugin *)plugin->next;
+               int64_t plugin_start = plugin->startproject;
+               int64_t plugin_end = plugin_start + plugin->length;
+               double plugin_end_pos = plugin->track->from_units(plugin_end);
+               int64_t track_plugin_end = track->to_units(plugin_end_pos, 0);
                if( plugin != moved_plugin && !plugin->silence() )
-                       drop_x0 = plugin_x1;
-               if( (plugin=(Plugin *)plugin->next) != 0 ) {
-                       if( plugin == moved_plugin || plugin->silence() ) continue;
-                       drop_x1 = plugin_x1;
+                       drop_start = track_plugin_end;
+               if( next_plugin ) {
+                       if( next_plugin == moved_plugin || next_plugin->silence() ) continue;
+                       drop_end = track_plugin_end;
                }
                else
-                       drop_x1 = INT64_MAX;
-               if( drop_position >= drop_x0 && // fits in the zone
-                   drop_position+moved_plugin->length < drop_x1 ) {
-                       return drop_position;
+                       drop_end = INT64_MAX;
+               if( plugin_position >= drop_start && // fits in the zone
+                   plugin_position+track_plugin_length < drop_end ) {
+                       return plugin_position;
                }
-               if( cursor_position < drop_x1 ) { // drop in the zone
-                       if( (drop_x1-drop_x0) >= moved_plugin->length ) {
-                               int64_t dx0 = llabs(cursor_position-drop_x0);
-                               int64_t dx1 = llabs(cursor_position-drop_x1);
-                               return dx0 < dx1 ? drop_x0 : drop_x1 - moved_plugin->length;
+               if( drop_position < drop_end ) { // drop in the zone
+                       if( (drop_end - drop_start) >= track_plugin_length ) {
+                               int64_t dx0 = llabs(drop_position - drop_start);
+                               int64_t dx1 = llabs(drop_position - drop_end);
+                               return dx0 < dx1 ? drop_start : drop_end - track_plugin_length;
                        }
                }
        }
@@ -622,19 +646,18 @@ int64_t TrackCanvas::drop_plugin_position(PluginSet *plugin_set, Plugin *moved_p
        return -1;
 }
 
-
 void TrackCanvas::draw(int mode, int hide_cursor)
 {
        const int debug = 0;
 
 
 // Swap pixmap layers
-       if(get_w() != background_pixmap->get_w() ||
-               get_h() != background_pixmap->get_h())
-       {
-               delete background_pixmap;
-               background_pixmap = new BC_Pixmap(this, get_w(), get_h());
-       }
+       if(get_w() != background_pixmap->get_w() ||
+               get_h() != background_pixmap->get_h())
+       {
+               delete background_pixmap;
+               background_pixmap = new BC_Pixmap(this, get_w(), get_h());
+       }
 
 // Cursor disappears after resize when this is called.
 // Cursor doesn't redraw after editing when this isn't called.
@@ -672,17 +695,11 @@ void TrackCanvas::test_timer()
 
 void TrackCanvas::draw_indexes(Indexable *indexable)
 {
+       IndexState *index_state = indexable->index_state;
 // Don't redraw raw samples
-       IndexState *index_state = 0;
-       index_state = indexable->index_state;
-
-
        if(index_state->index_zoom > mwindow->edl->local_session->zoom_sample)
                return;
-
-
        draw_resources(0, 1, indexable);
-
        draw_overlays();
        flash(0);
 }
@@ -695,9 +712,6 @@ void TrackCanvas::draw_resources(int mode,
 
        if(debug) PRINT_TRACE
 
-       if(!mwindow->edl->session->show_assets) return;
-
-
 // can't stop thread here, because this is called for every pane
 //     if(mode != IGNORE_THREAD && !indexes_only)
 //             gui->resource_thread->stop_draw(!indexes_only);
@@ -787,24 +801,29 @@ void TrackCanvas::draw_resources(int mode,
                                if(pixmap_w && pixmap_h)
                                {
 // Create pixmap if it doesn't exist
-                                       ResourcePixmap* pixmap = create_pixmap(edit,
-                                               edit_x,
-                                               pixmap_x,
-                                               pixmap_w,
-                                               pixmap_h);
+                                       ResourcePixmap* pixmap = create_pixmap(edit, edit_x,
+                                               pixmap_x, pixmap_w, pixmap_h);
 // Resize it if it's bigger
-                                       if(pixmap_w > pixmap->pixmap_w ||
-                                               pixmap_h > pixmap->pixmap_h)
+                                       if( pixmap_w > pixmap->pixmap_w ||
+                                           pixmap_h > pixmap->pixmap_h)
                                                pixmap->resize(pixmap_w, pixmap_h);
-                                       pixmap->draw_data(this,
-                                               edit,
-                                               edit_x,
-                                               edit_w,
-                                               pixmap_x,
-                                               pixmap_w,
-                                               pixmap_h,
-                                               mode,
-                                               indexes_only);
+                                       pixmap->update_settings(edit, edit_x, edit_w,
+                                               pixmap_x, pixmap_w, pixmap_h);
+// Draw data
+                                       if( current->show_assets() )
+                                               pixmap->draw_data(this,
+                                                       edit, edit_x, edit_w,
+                                                       pixmap_x, pixmap_w, pixmap_h,
+                                                       mode, indexes_only);
+                                       else {
+                                               set_bg_color(BLACK);
+                                               clear_box(0,0, pixmap_w,pixmap_h, pixmap);
+                                       }
+// Draw title
+                                       if( current->show_titles() )
+                                               pixmap->draw_title(this,
+                                                       edit, edit_x, edit_w,
+                                                       pixmap_x, pixmap_w);
 // Resize it if it's smaller
                                        if(pixmap_w < pixmap->pixmap_w ||
                                                pixmap_h < pixmap->pixmap_h)
@@ -945,27 +964,22 @@ void TrackCanvas::get_pixmap_size(Edit *edit,
 //     }
 
        pixmap_h = mwindow->edl->local_session->zoom_track;
-       if(mwindow->edl->session->show_titles) pixmap_h += mwindow->theme->get_image("title_bg_data")->get_h();
+       Track *track = edit->edits->track;
+       if( track->show_titles() )
+               pixmap_h += mwindow->theme->get_image("title_bg_data")->get_h();
 //printf("get_pixmap_size %d %d %d %d\n", edit_x, edit_w, pixmap_x, pixmap_w);
 }
 
 void TrackCanvas::edit_dimensions(Edit *edit,
-       int64_t &x,
-       int64_t &y,
-       int64_t &w,
-       int64_t &h)
+       int64_t &x, int64_t &y, int64_t &w, int64_t &h)
 {
-//     w = Units::round(edit->track->from_units(edit->length) *
-//             mwindow->edl->session->sample_rate /
-//             mwindow->edl->local_session->zoom_sample);
-
-       h = resource_h();
-
        x = Units::round(edit->track->from_units(edit->startproject) *
                        mwindow->edl->session->sample_rate /
                        mwindow->edl->local_session->zoom_sample -
                        mwindow->edl->local_session->view_start[pane->number]);
 
+       y = edit->edits->track->y_pixel - mwindow->edl->local_session->track_start[pane->number];
+
 // Method for calculating w so when edits are together we never get off by one error due to rounding
        int64_t x_next = Units::round(edit->track->from_units(edit->startproject + edit->length) *
                        mwindow->edl->session->sample_rate /
@@ -973,10 +987,12 @@ void TrackCanvas::edit_dimensions(Edit *edit,
                        mwindow->edl->local_session->view_start[pane->number]);
        w = x_next - x;
 
-       y = edit->edits->track->y_pixel - mwindow->edl->local_session->track_start[pane->number];
-
-       if(mwindow->edl->session->show_titles)
-               h += mwindow->theme->get_image("title_bg_data")->get_h();
+       int edit_h = 0;
+       if( edit->track->show_titles() )
+               edit_h += mwindow->theme->get_image("title_bg_data")->get_h();
+       if( edit->track->show_assets() )
+               edit_h += resource_h();
+       h = edit_h;
 }
 
 void TrackCanvas::track_dimensions(Track *track, int64_t &x, int64_t &y, int64_t &w, int64_t &h)
@@ -1023,7 +1039,7 @@ void TrackCanvas::draw_paste_destination()
 
                int has_audio = 0, has_video = 0;
                double paste_audio_length = 0, paste_video_length = 0;
-                double paste_audio_position = -1, paste_video_position = -1;
+               double paste_audio_position = -1, paste_video_position = -1;
 
                if( indexable ) {
                        has_audio = indexable->have_audio();
@@ -1098,9 +1114,9 @@ void TrackCanvas::draw_paste_destination()
                                }
 
 // Get the x coordinate
-                               x = Units::to_int64(position * 
+                               x = Units::to_int64(position *
                                        mwindow->edl->session->sample_rate /
-                                       mwindow->edl->local_session->zoom_sample) - 
+                                       mwindow->edl->local_session->zoom_sample) -
                                        mwindow->edl->local_session->view_start[pane->number];
 
                                double paste_position = -1.;
@@ -1134,6 +1150,7 @@ void TrackCanvas::draw_paste_destination()
                                                                from_units(drop_edit_position(&insertion,
                                                                        mwindow->session->drag_edit,
                                                                        mwindow->session->drag_edit->length));
+                                                       current_aedit++;
                                                }
                                        }
                                        if( paste_position >= 0 ) {
@@ -1176,6 +1193,7 @@ void TrackCanvas::draw_paste_destination()
                                                                from_units(drop_edit_position(&insertion,
                                                                        mwindow->session->drag_edit,
                                                                        mwindow->session->drag_edit->length));
+                                                       current_vedit++;
                                                }
                                        }
                                        if( paste_position >= 0 ) {
@@ -1197,10 +1215,6 @@ void TrackCanvas::draw_paste_destination()
                                        int h = dest->vertical_span(mwindow->theme);
 
 //printf("TrackCanvas::draw_paste_destination 2 %d %d %d %d\n", x, y, w, h);
-                                       if (insertion)
-                                               draw_highlight_insertion(x, y, w, h);
-                                       else
-                                               draw_highlight_rectangle(x, y, w, h);
                                        if(x < -BC_INFINITY) {
                                                w -= -BC_INFINITY - x;
                                                x += -BC_INFINITY - x;
@@ -1209,7 +1223,10 @@ void TrackCanvas::draw_paste_destination()
 // if(pane->number == TOP_RIGHT_PANE)
 // printf("TrackCanvas::draw_paste_destination %d %d %d %d %d\n",
 // __LINE__, x, y, w, h);
-                                       draw_highlight_rectangle(x, y, w, h);
+                                       if (insertion)
+                                               draw_highlight_insertion(x, y, w, h);
+                                       else
+                                               draw_highlight_rectangle(x, y, w, h);
                                }
                        }
                }
@@ -1225,13 +1242,14 @@ void TrackCanvas::plugin_dimensions(Plugin *plugin, int64_t &x, int64_t &y, int6
        w = Units::round(plugin->track->from_units(plugin->length) *
                mwindow->edl->session->sample_rate /
                mwindow->edl->local_session->zoom_sample);
-       y = plugin->track->y_pixel -
-               mwindow->edl->local_session->track_start[pane->number] +
-               mwindow->edl->local_session->zoom_track +
-               plugin->plugin_set->get_number() *
-               mwindow->theme->get_image("plugin_bg_data")->get_h();
-       if(mwindow->edl->session->show_titles)
+       y = plugin->track->y_pixel
+               - mwindow->edl->local_session->track_start[pane->number];
+       if( plugin->track->show_titles() )
                y += mwindow->theme->get_image("title_bg_data")->get_h();
+       if( plugin->track->show_assets() )
+               y += resource_h();
+       y += plugin->plugin_set->get_number() *
+                       mwindow->theme->get_image("plugin_bg_data")->get_h();
        h = mwindow->theme->get_image("plugin_bg_data")->get_h();
 }
 
@@ -1277,7 +1295,7 @@ void TrackCanvas::draw_highlight_rectangle(int x, int y, int w, int h)
        h = MIN(h, get_h() + 20);
        if(w > 0 && h > 0)
        {
-               set_color(WHITE);
+               set_color(mwindow->preferences->highlight_inverse);
                set_inverse();
                //draw_rectangle(x, y, w, h);
                draw_rectangle(x + 1, y + 1, w - 2, h - 2);
@@ -1339,7 +1357,7 @@ void TrackCanvas::draw_highlight_insertion(int x, int y, int w, int h)
        }
        w = MIN(w, get_w() + 20);
        h = MIN(h, get_h() + 20);
-       set_color(WHITE);
+       set_color(mwindow->preferences->highlight_inverse);
        set_inverse();
        draw_rectangle(x, y, w, h);
        draw_rectangle(x + 1, y + 1, w - 2, h - 2);
@@ -1364,42 +1382,36 @@ void TrackCanvas::get_handle_coords(Edit *edit, int64_t &x, int64_t &y, int64_t
 
        edit_dimensions(edit, x, y, w, h);
 
-       if(mwindow->edl->session->show_titles)
-       {
+       if( edit->track->show_titles() )
                y += mwindow->theme->get_image("title_bg_data")->get_h();
-       }
-       else
-       {
-               y = 0;
-       }
 
        if(side == EDIT_OUT)
-       {
                x += w - handle_w;
-       }
 
        h = handle_h;
        w = handle_w;
 }
 
-void TrackCanvas::get_transition_coords(int64_t &x, int64_t &y, int64_t &w, int64_t &h)
+void TrackCanvas::get_transition_coords(Edit *edit,
+               int64_t &x, int64_t &y, int64_t &w, int64_t &h)
 {
-//printf("TrackCanvas::get_transition_coords 1\n");
-//     int transition_w = mwindow->theme->transitionhandle_data[0]->get_w();
-//     int transition_h = mwindow->theme->transitionhandle_data[0]->get_h();
-       int transition_w = 30;
-       int transition_h = 30;
-//printf("TrackCanvas::get_transition_coords 1\n");
-
-       if(mwindow->edl->session->show_titles)
-               y += mwindow->theme->get_image("title_bg_data")->get_h();
-//printf("TrackCanvas::get_transition_coords 2\n");
+       int transition_w = 30, transition_h = 30;
+       int has_titles = edit->track->show_titles();
+       int has_assets = edit->track->show_assets();
+       double title_bg_h = mwindow->theme->get_image("title_bg_data")->get_h();
+       double asset_h = resource_h();
+       double ys = has_assets ? asset_h : has_titles ? title_bg_h : 0;
+       double dy = has_titles ?
+               ( has_assets ? title_bg_h + asset_h/2 : title_bg_h/2 ) :
+               ( has_assets ? asset_h/2 : 0) ;
+       double title_h = mwindow->theme->title_h;
+       if( dy < title_h / 2 ) { ys = title_h;  dy = ys / 2; }
+       y += dy;
 
-       y += (h - mwindow->theme->get_image("title_bg_data")->get_h()) / 2 - transition_h / 2;
        x -= transition_w / 2;
-
-       h = transition_h;
+       y -= transition_h / 2;
        w = transition_w;
+       h = transition_h;
 }
 
 void TrackCanvas::draw_highlighting()
@@ -1414,21 +1426,18 @@ void TrackCanvas::draw_highlighting()
 //printf("TrackCanvas::draw_highlighting 1 %p %p\n",
 //     mwindow->session->track_highlighted, mwindow->session->edit_highlighted);
                        if(mwindow->session->edit_highlighted) {
-//printf("TrackCanvas::draw_highlighting 2\n");
                                if((mwindow->session->current_operation == DRAG_ATRANSITION &&
                                        mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
                                        (mwindow->session->current_operation == DRAG_VTRANSITION &&
                                        mwindow->session->track_highlighted->data_type == TRACK_VIDEO)) {
-//printf("TrackCanvas::draw_highlighting 2\n");
-                                       edit_dimensions(mwindow->session->edit_highlighted, x, y, w, h);
-//printf("TrackCanvas::draw_highlighting 2\n");
-
+                                       edit_dimensions(mwindow->session->edit_highlighted,
+                                               x, y, w, h);
                                        if(MWindowGUI::visible(x, x + w, 0, get_w()) &&
                                                MWindowGUI::visible(y, y + h, 0, get_h())) {
                                                draw_box = 1;
-                                               get_transition_coords(x, y, w, h);
+                                               get_transition_coords(mwindow->session->edit_highlighted,
+                                                       x, y, w, h);
                                        }
-//printf("TrackCanvas::draw_highlighting 3\n");
                                }
                        }
                        break;
@@ -1594,14 +1603,14 @@ void TrackCanvas::draw_plugins()
        char string[BCTEXTLEN];
        int current_on = 0;
        int current_show = 0;
-
-
-//     if(!mwindow->edl->session->show_assets) goto done;
+       int current_preset = 0;
 
        for(int i = 0; i < plugin_on_toggles.total; i++)
                plugin_on_toggles.values[i]->in_use = 0;
        for(int i = 0; i < plugin_show_toggles.total; i++)
                plugin_show_toggles.values[i]->in_use = 0;
+       for(int i = 0; i < preset_edit_buttons.total; i++)
+               plugin_show_toggles.values[i]->in_use = 0;
 
 
        for(Track *track = mwindow->edl->tracks->first;
@@ -1709,9 +1718,21 @@ void TrackCanvas::draw_plugins()
                                                                }
                                                                current_show++;
                                                        }
-
-
-
+                                                       toggle_x -= PluginPresetEdit::calculate_w(mwindow) + 10;
+                                                       if(toggle_x > min_x)
+                                                       {
+                                                               if(current_preset >= preset_edit_buttons.total)
+                                                               {
+                                                                       PluginPresetEdit *preset_edit = new PluginPresetEdit(mwindow, toggle_x, toggle_y, plugin);
+                                                                       add_subwindow(preset_edit);
+                                                                       preset_edit_buttons.append(preset_edit);
+                                                               }
+                                                               else
+                                                               {
+                                                                       preset_edit_buttons.values[current_preset]->update(toggle_x, toggle_y, plugin);
+                                                               }
+                                                               current_preset++;
+                                                       }
                                                }
                                        }
                                }
@@ -1721,6 +1742,10 @@ void TrackCanvas::draw_plugins()
 
 // Remove unused toggles
 
+       while(current_preset < preset_edit_buttons.total)
+       {
+               preset_edit_buttons.remove_object_number(current_preset);
+       }
        while(current_show < plugin_show_toggles.total)
        {
                plugin_show_toggles.remove_object_number(current_show);
@@ -1730,7 +1755,6 @@ void TrackCanvas::draw_plugins()
        {
                plugin_on_toggles.remove_object_number(current_on);
        }
-
 }
 
 void TrackCanvas::refresh_plugintoggles()
@@ -1745,6 +1769,46 @@ void TrackCanvas::refresh_plugintoggles()
                PluginShow *show = plugin_show_toggles.values[i];
                show->reposition_window(show->get_x(), show->get_y());
        }
+       for(int i = 0; i < preset_edit_buttons.total; i++)
+       {
+               PluginPresetEdit *preset_edit = preset_edit_buttons.values[i];
+               preset_edit->reposition_window(preset_edit->get_x(), preset_edit->get_y());
+       }
+}
+
+void TrackCanvas::draw_hard_edges()
+{
+       int64_t x, y, w, h;
+
+       for(Track *track = mwindow->edl->tracks->first; track; track = track->next) {
+               for(Edit *edit = track->edits->first; edit; edit = edit->next) {
+                       if( !edit->hard_left && !edit->hard_right ) continue;
+                       edit_dimensions(edit, x, y, w, h);
+                       set_color(GREEN);
+                       set_opaque();
+                       int y1 = y;
+                       if( track->show_titles() )
+                               y1 += mwindow->theme->get_image("title_bg_data")->get_h();
+                       if( track->show_assets() )
+                               y1 += resource_h();
+                       if( y1 == y )
+                               y1 += mwindow->theme->title_h;
+                       if( edit->hard_left ) {
+                               ArrayList<int> xpt, ypt;
+                               xpt.append(x);              ypt.append(y1);
+                               xpt.append(x+HANDLE_W);     ypt.append(y1);
+                               xpt.append(x);              ypt.append(y1-HANDLE_H);
+                               fill_polygon(&xpt, &ypt);
+                       }
+                       if( edit->hard_right ) {
+                               ArrayList<int> xpt, ypt;   int x1 = x+w-1;
+                               xpt.append(x1);            ypt.append(y1);
+                               xpt.append(x1-HANDLE_W);   ypt.append(y1);
+                               xpt.append(x1);            ypt.append(y1-HANDLE_H);
+                               fill_polygon(&xpt, &ypt);
+                       }
+               }
+       }
 }
 
 void TrackCanvas::draw_inout_points()
@@ -1763,7 +1827,7 @@ void TrackCanvas::draw_drag_handle()
                        mwindow->edl->local_session->zoom_sample -
                        mwindow->edl->local_session->view_start[pane->number]);
 //printf("TrackCanvas::draw_drag_handle 2 %d %jd\n", pane->number, pixel1);
-               set_color(GREEN);
+               set_color(!snapped ? GREEN : (snapped=0, YELLOW));
                set_inverse();
 //printf("TrackCanvas::draw_drag_handle 3\n");
                draw_line(pixel1, 0, pixel1, get_h());
@@ -1777,38 +1841,38 @@ void TrackCanvas::draw_transitions()
 {
        int64_t x, y, w, h;
 
-//     if(!mwindow->edl->session->show_assets) return;
-
        for(Track *track = mwindow->edl->tracks->first; track; track = track->next) {
+               if( !track->show_transitions() ) continue;
+
                for(Edit *edit = track->edits->first; edit; edit = edit->next) {
                        if(!edit->transition) continue;
                        edit_dimensions(edit, x, y, w, h);
-                       int strip_x = x, strip_y = y;
-                       if(mwindow->edl->session->show_titles)
-                               strip_y += mwindow->theme->get_image("title_bg_data")->get_h();
-                       get_transition_coords(x, y, w, h);
+                       int strip_x = x, edit_y = y;
+                       get_transition_coords(edit, x, y, w, h);
+                       int strip_y = y - mwindow->theme->get_image("plugin_bg_data")->get_h();
+                       if( track->show_assets() && track->show_titles() )
+                               edit_y += mwindow->theme->get_image("title_bg_data")->get_h();
+                       if( strip_y < edit_y ) strip_y = edit_y;
+
                        int strip_w = Units::round(edit->track->from_units(edit->transition->length) *
                                mwindow->edl->session->sample_rate / mwindow->edl->local_session->zoom_sample);
                        if( MWindowGUI::visible(x, x + w, 0, get_w()) &&
-                               MWindowGUI::visible(y, y + h, 0, get_h()) )
-                       {
+                           MWindowGUI::visible(y, y + h, 0, get_h()) ) {
                                PluginServer *server = mwindow->scan_plugindb(edit->transition->title,
                                                track->data_type);
                                if( !server ) continue;
                                VFrame *picon = server->get_picon();
                                if( !picon ) continue;
-                               draw_vframe(picon, x, y, w, h, 0, 0, picon->get_w(), picon->get_h());
+                               int picon_w = picon->get_w(), picon_h = picon->get_h();
+                               int track_h = edit->track->vertical_span(mwindow->theme);
+                               if( picon_h > track_h ) picon_h = track_h;
+                               draw_vframe(picon, x, y, w, h, 0, 0, picon_w, picon_h);
                        }
                        if(MWindowGUI::visible(strip_x, strip_x + strip_w, 0, get_w()) &&
-                               MWindowGUI::visible(strip_y, strip_y + h, 0, get_h()))
-                       {
+                               MWindowGUI::visible(strip_y, strip_y + h, 0, get_h())) {
                                int x = strip_x, w = strip_w;
-                               if(x < 0)
-                               {
-                                       w -= -x;
-                                       x = 0;
-                               }
-                               if(w + x > get_w()) w -= (w + x) - get_w();
+                               if( x < 0 ) {  w -= -x;  x = 0; }
+                               if( w + x > get_w() ) w -= (w + x) - get_w();
 
                                draw_3segmenth( x, strip_y, w, strip_x, strip_w,
                                        mwindow->theme->get_image("plugin_bg_data"), 0);
@@ -1852,19 +1916,30 @@ void TrackCanvas::draw_loop_points()
 //printf("TrackCanvas::draw_loop_points 7\n");
 }
 
-void TrackCanvas::draw_brender_start()
+void TrackCanvas::draw_brender_range()
 {
-       if(mwindow->preferences->use_brender)
+       if( !mwindow->preferences->use_brender || !mwindow->brender_active ) return;
+       if( mwindow->edl->session->brender_start >= mwindow->edl->session->brender_end ) return;
+       if( mwindow->edl->session->brender_end > 0 )
        {
-               int64_t x = Units::round(mwindow->edl->session->brender_start *
+               int64_t x1 = Units::round(mwindow->edl->session->brender_start *
+                       mwindow->edl->session->sample_rate /
+                       mwindow->edl->local_session->zoom_sample -
+                       mwindow->edl->local_session->view_start[pane->number]);
+               if(MWindowGUI::visible(x1, x1 + 1, 0, get_w()))
+               {
+                       set_color(RED);
+                       draw_line(x1, 0, x1, get_h());
+               }
+               int64_t x2 = Units::round(mwindow->edl->session->brender_end *
                        mwindow->edl->session->sample_rate /
                        mwindow->edl->local_session->zoom_sample -
                        mwindow->edl->local_session->view_start[pane->number]);
 
-               if(MWindowGUI::visible(x, x + 1, 0, get_w()))
+               if(MWindowGUI::visible(x2, x2 + 1, 0, get_w()))
                {
                        set_color(RED);
-                       draw_line(x, 0, x, get_h());
+                       draw_line(x2, 0, x2, get_h());
                }
        }
 }
@@ -1934,7 +2009,7 @@ int TrackCanvas::do_keyframes(int cursor_x,
        for(Track *track = mwindow->edl->tracks->first;
                track && !result;
                track = track->next) {
-               Auto *auto_keyframe = 0;
+               Auto *auto_keyframe = 0;
                Automation *automation = track->automation;
 
 
@@ -1968,22 +2043,33 @@ int TrackCanvas::do_keyframes(int cursor_x,
                                        case Autos::AUTOMATION_TYPE_FLOAT: {
                                                Automation automation(0, track);
                                                int grouptype = automation.autogrouptype(i, track);
+                                               if( buttonpress && i == AUTOMATION_SPEED ) {
+                                                       mwindow->speed_before();
+                                               }
+
                                                if(draw) // Do dropshadow
                                                        result = do_float_autos(track, autos,
-                                                               cursor_x, cursor_y, draw, 
+                                                               cursor_x, cursor_y, draw,
                                                                buttonpress, 1, 1, MDGREY,
                                                                auto_keyframe, grouptype);
-
                                                result = do_float_autos(track, autos,
                                                        cursor_x, cursor_y, draw, buttonpress,
                                                        0, 0, GWindowGUI::auto_colors[i],
                                                        auto_keyframe, grouptype);
+
+                                               if( !result && buttonpress && i == AUTOMATION_SPEED )
+                                                       mwindow->speed_after(-1);
+                                               int current_grouptype = mwindow->edl->local_session->zoombar_showautotype;
+                                               if( result && buttonpress && grouptype != current_grouptype ) {
+                                                       mwindow->edl->local_session->zoombar_showautotype = grouptype;
+                                                       mwindow->gui->zoombar->update_autozoom();
+                                               }
                                                break; }
 
                                        case Autos::AUTOMATION_TYPE_INT: {
                                                if(draw) // Do dropshadow
                                                        result = do_int_autos(track, autos,
-                                                               cursor_x, cursor_y, draw, 
+                                                               cursor_x, cursor_y, draw,
                                                                buttonpress, 1, 1, MDGREY,
                                                                auto_keyframe);
                                                result = do_int_autos(track, autos,
@@ -2009,10 +2095,8 @@ int TrackCanvas::do_keyframes(int cursor_x,
                                                if (buttonpress != 3)
                                                {
                                                        if(i == AUTOMATION_FADE || i == AUTOMATION_SPEED)
-                                                               synchronize_autos(0,
-                                                                       track,
-                                                                       (FloatAuto*)mwindow->session->drag_auto,
-                                                                       1);
+                                                               fill_ganged_autos(get_double_click(), 0, track,
+                                                                       (FloatAuto*)mwindow->session->drag_auto);
                                                        mwindow->session->current_operation = pre_auto_operations[i];
                                                        update_drag_caption();
                                                        rerender = 1;
@@ -2039,9 +2123,7 @@ int TrackCanvas::do_keyframes(int cursor_x,
                        }
                }
 
-               if(!result &&
-                       session->auto_conf->plugins /* &&
-                       mwindow->edl->session->show_assets */) {
+               if(!result && session->auto_conf->plugins) {
                        Plugin *plugin;
                        KeyFrame *keyframe;
                        result = do_plugin_autos(track, cursor_x, cursor_y,
@@ -2093,34 +2175,37 @@ void TrackCanvas::draw_keyframe_reticle()
        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( dragging && !mwindow->session->drag_auto ) dragging = 0;
 
-       if( keyframe_hairline == HAIRLINE_DRAGGING && dragging ) {
-               if( mwindow->session->drag_auto && get_buttonpress() == 1 ) {
-                       draw_hairline(mwindow->session->drag_auto, RED);
-                       return;
-               }
+       int autoidx = dragging && keyframe_hairline != HAIRLINE_ALWAYS ?
+               mwindow->session->drag_auto->autos->autoidx : -1;
+
+       if( get_buttonpress() == 1 && dragging &&
+            keyframe_hairline == HAIRLINE_DRAGGING ) {
+               draw_hairline(mwindow->session->drag_auto, RED, 1);
+               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 ) {
+               int show = dragging || keyframe_hairline == HAIRLINE_ALWAYS ? 1 : 0;
+               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;
+                               if( autoidx >= 0 && autos->autoidx != autoidx ) continue;
                                for( Auto *auto_keyframe=autos->first; auto_keyframe;
                                     auto_keyframe = auto_keyframe->next ) {
-                                       draw_hairline(auto_keyframe, GREEN);
+                                       draw_hairline(auto_keyframe, BLUE, show);
                                }
                        }
-
-                       if( dragging && mwindow->session->drag_auto ) {
-                               draw_hairline(mwindow->session->drag_auto, RED);
-                       }
                }
+
+               if( dragging )
+                       draw_hairline(mwindow->session->drag_auto, RED, 1);
        }
 }
 
@@ -2191,14 +2276,14 @@ void TrackCanvas::draw_cropped_line(int x1,
 }
 
 
-void TrackCanvas::draw_floatauto(FloatAuto *current, 
-       int x, 
-       int y, 
-       int in_x, 
-       int in_y, 
-       int out_x, 
-       int out_y, 
-       int center_pixel, 
+void TrackCanvas::draw_floatauto(FloatAuto *current,
+       int x,
+       int y,
+       int in_x,
+       int in_y,
+       int out_x,
+       int out_y,
+       int center_pixel,
        int zoom_track,
        int color)
 {
@@ -2219,7 +2304,7 @@ void TrackCanvas::draw_floatauto(FloatAuto *current,
                draw_box(x1, y1, x2 - x1, y2 - y1);
        }
 
-// show bezier control points (only) if this 
+// show bezier control points (only) if this
 // floatauto doesn't adjust it's tangents automatically
        if(current->curve_mode != FloatAuto::FREE &&
           current->curve_mode != FloatAuto::TFREE)
@@ -2247,22 +2332,22 @@ inline void TrackCanvas::draw_floatauto_ctrlpoint(
 
        y    += center_pixel;
        cp_y += center_pixel;
-       
+
        // drawing the tangent as a dashed line...
        int const dash = HANDLE_W;
        int const gap  = HANDLE_W / 2;
        float sx = 3 * (cp_x - x) / 4.;
        float ex = 0;
-       
+
        // q is the x displacement for a unit line of slope
        float q = (sx > 0 ? 1 : -1) / sqrt(1 + slope * slope);
-       
+
        float dist = 1/q * sx;
        if( dist > dash )
                ex = sx - q * dash;
-       
+
        set_color(color);
-       do {    
+       do {
                float sy = slope * sx, ey = slope * ex;
                draw_line(quantize(sx + x), quantize(sy + y), quantize(ex + x), quantize(ey + y));
                sx = ex - q * gap;
@@ -2345,10 +2430,10 @@ inline float test_curve_line( int x0, int y0, int ctrl_x, int ctrl_y,
 }
 
 
-inline 
+inline
 float levered_position(float position, float ref_pos)
 {
-       if( 1e-6 > fabs(ref_pos) || isnan(ref_pos)) 
+       if( 1e-6 > fabs(ref_pos) || isnan(ref_pos))
                return 0.0;
        return ref_pos / position;
 }
@@ -2370,7 +2455,7 @@ float TrackCanvas::value_to_percentage(float auto_value, int autogrouptype)
 
 
 int TrackCanvas::test_floatauto(FloatAuto *current, int x, int y, int in_x,
-       int in_y, int out_x, int out_y, int center_pixel, int zoom_track, 
+       int in_y, int out_x, int out_y, int center_pixel, int zoom_track,
        int cursor_x, int cursor_y, int buttonpress, int autogrouptype)
 {
        int result = 0;
@@ -2421,7 +2506,7 @@ int TrackCanvas::test_floatauto(FloatAuto *current, int x, int y, int in_x,
                if( WITHIN(x1,x2,y1,y2))
                {       // cursor hits node
                        result = 1;
-                       
+
                        if(buttonpress && (buttonpress != 3))
                        {
                                INIT_DRAG(current->position, value_to_percentage(current->get_value(), autogrouptype))
@@ -2438,13 +2523,13 @@ int TrackCanvas::test_floatauto(FloatAuto *current, int x, int y, int in_x,
                                // could be ctrl-click or ctrl-drag
                                // click would cycle through tangent modes
                                ((FloatAuto*)current)->toggle_curve_mode();
-                               
+
                                // drag will start dragging the tangent, if applicable
                                INIT_DRAG(current->position, value_to_percentage(current->get_value(), autogrouptype))
                                mwindow->session->drag_handle = 0;
                        }
                }
-                       
+
                float lever = 0.0; // we use the tangent as a draggable lever. 1.0 is at the ctrl point
 
 // Test in control
@@ -2493,15 +2578,15 @@ int TrackCanvas::test_floatauto(FloatAuto *current, int x, int y, int in_x,
 #undef WITHIN
 #undef INIT_DRAG
 
-// if(buttonpress) 
-// printf("TrackCanvas::test_floatauto 2 drag_handle=%d ctrl_down=%d cursor_x=%d cursor_y=%d x1=%d x2=%d y1=%d y2=%d\n", 
+// if(buttonpress)
+// printf("TrackCanvas::test_floatauto 2 drag_handle=%d ctrl_down=%d cursor_x=%d cursor_y=%d x1=%d x2=%d y1=%d y2=%d\n",
 // mwindow->session->drag_handle,
 // ctrl_down(),
 // cursor_x,
 // cursor_y,
 // x1, x2, y1, y2);
        if(buttonpress && (buttonpress != 3) && result)
-               {
+       {
                mwindow->undo->update_undo_before();
        }
 
@@ -2618,7 +2703,10 @@ int TrackCanvas::test_floatline(int center_pixel,
                {
                        Auto *current;
                        mwindow->undo->update_undo_before();
-                       current = mwindow->session->drag_auto = autos->insert_auto(position1);
+                       double position = autos->track->from_units(position1);
+                       position = mwindow->edl->align_to_frame(position, 0);
+                       int64_t new_position = autos->track->to_units(position,0);
+                       current = mwindow->session->drag_auto = autos->insert_auto(new_position);
                        ((FloatAuto*)current)->set_value(value);
                        mwindow->session->drag_start_percentage = value_to_percentage(value, autogrouptype);
                        mwindow->session->drag_start_position = current->position;
@@ -2633,69 +2721,68 @@ int TrackCanvas::test_floatline(int center_pixel,
 }
 
 
-void TrackCanvas::synchronize_autos(float change,
-               Track *skip, FloatAuto *fauto, int fill_gangs)
+void TrackCanvas::fill_ganged_autos(int all, float change, Track *skip, FloatAuto *fauto)
 {
+       if( !skip->gang ) return;
 // 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 > 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
-                                       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 {
+       double position = skip->from_units(fauto->position);
+       int autoidx = fauto->autos->autoidx;
+
+       for(Track *current = mwindow->edl->tracks->first; current; current = NEXT) {
+               if( (all || current->data_type == skip->data_type) &&
+                   current->gang && current->record && current != skip ) {
+                       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];
+                       int64_t current_position = current->to_units(position, 1);
+                       FloatAuto *keyframe = (FloatAuto*)fade_autos->get_auto_at_position(position);
+                       if( keyframe ) {
 // keyframe exists, just change it
-                                       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);
+                               float value = keyframe->get_value();
+                               float new_value = value + change;
+                               CLAMP(new_value, auto_min, auto_max);
+                               keyframe->adjust_to_new_coordinates(current_position, new_value);
                        }
+                       else if( mwindow->edl->session->auto_keyframes ) {
+// create keyframe on neighbouring track at the point in time given by fauto
+                               FloatAuto *previous = 0, *next = 0;
+                               float value = fade_autos->get_value(current_position, PLAY_FORWARD, previous, next);
+                               float new_value = value + change;
+                               CLAMP(new_value, auto_min, auto_max);
+                               keyframe = (FloatAuto*)fade_autos->insert_auto(current_position);
+                               keyframe->set_value(new_value);
+                       }
+                       else
+                               continue;
+                       mwindow->session->drag_auto_gang->append((Auto *)keyframe);
                }
        }
-       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(keyframe_position, new_value);
-               }
+}
 
+void TrackCanvas::update_ganged_autos(float change, Track *skip, FloatAuto *fauto)
+{
+       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(keyframe_position, new_value);
        }
-       else {
+}
+
+void TrackCanvas::clear_ganged_autos()
+{
 // remove the gangs
-               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);
-               }
-               mwindow->session->drag_auto_gang->remove_all();
+       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);
        }
+       mwindow->session->drag_auto_gang->remove_all();
 }
 
 
@@ -2775,6 +2862,7 @@ void TrackCanvas::calculate_viewport(Track *track,
        double &zoom_sample,
        double &zoom_units)
 {
+
        view_start = (double)mwindow->edl->local_session->view_start[pane->number] *
                mwindow->edl->local_session->zoom_sample /
                mwindow->edl->session->sample_rate;
@@ -2784,16 +2872,23 @@ void TrackCanvas::calculate_viewport(Track *track,
                mwindow->edl->local_session->zoom_sample /
                mwindow->edl->session->sample_rate;
        unit_end = track->to_doubleunits(view_end);
-       yscale = mwindow->edl->local_session->zoom_track;
-//printf("TrackCanvas::calculate_viewport yscale=%.0f\n", yscale);
-       center_pixel = (int)(track->y_pixel -
-                       mwindow->edl->local_session->track_start[pane->number] +
-                       yscale / 2) +
-               (mwindow->edl->session->show_titles ?
-                       mwindow->theme->get_image("title_bg_data")->get_h() :
-                       0);
-       zoom_sample = mwindow->edl->local_session->zoom_sample;
 
+       int y = track->y_pixel
+                       - mwindow->edl->local_session->track_start[pane->number];
+       int has_titles = track->show_titles();
+       int has_assets = track->show_assets();
+       double title_bg_h = mwindow->theme->get_image("title_bg_data")->get_h();
+       double asset_h = resource_h();
+       double title_h = mwindow->theme->title_h;
+       double ys = has_assets ? asset_h : has_titles ? title_bg_h : 0;
+       double dy = has_titles ?
+               ( has_assets ? title_bg_h + asset_h/2 : title_bg_h/2) :
+               ( has_assets ? asset_h/2 : 0) ;
+       if( dy < title_h/2 ) { ys = title_h;  dy = ys / 2; }
+       yscale = ys;
+       center_pixel = y + dy;
+
+       zoom_sample = mwindow->edl->local_session->zoom_sample;
        zoom_units = track->to_doubleunits(zoom_sample / mwindow->edl->session->sample_rate);
 }
 
@@ -2979,7 +3074,7 @@ int TrackCanvas::do_float_autos(Track *track, Autos *autos, int cursor_x, int cu
                                (int)ax, (int)ax2, cursor_x, cursor_y,
                                buttonpress, autogrouptype);
                }
-               if( draw ) 
+               if( draw )
                        draw_floatline(center_pixel,
                                (FloatAuto*)previous, (FloatAuto*)current,
                                (FloatAutos*)autos, unit_start, zoom_units, yscale,
@@ -3284,11 +3379,13 @@ int TrackCanvas::do_plugin_autos(Track *track, int cursor_x, int cursor_y,
        for(int i = 0; i < track->plugin_set.total && !result; i++)
        {
                PluginSet *plugin_set = track->plugin_set.values[i];
-               int center_pixel = (int)(track->y_pixel -
-                       mwindow->edl->local_session->track_start[pane->number] +
-                       mwindow->edl->local_session->zoom_track +
-                       (i + 0.5) * mwindow->theme->get_image("plugin_bg_data")->get_h() +
-                       (mwindow->edl->session->show_titles ? mwindow->theme->get_image("title_bg_data")->get_h() : 0));
+               int center_pixel = track->y_pixel -
+                       mwindow->edl->local_session->track_start[pane->number];
+               if( track->show_titles() )
+                       center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
+               if( track->show_assets() )
+                       center_pixel += resource_h();
+               center_pixel += (i + 0.5) * mwindow->theme->get_image("plugin_bg_data")->get_h();
 
                for(Plugin *plugin = (Plugin*)plugin_set->first;
                        plugin && !result;
@@ -3361,10 +3458,10 @@ int TrackCanvas::do_plugin_autos(Track *track, int cursor_x, int cursor_y,
        return result;
 }
 
-int TrackCanvas::draw_hairline(Auto *auto_keyframe, int color)
+int TrackCanvas::draw_hairline(Auto *auto_keyframe, int color, int show)
 {
        Track *track = auto_keyframe->autos->track;
-       int autogrouptype = auto_keyframe->autos->get_type();
+       int autogrouptype = auto_keyframe->autos->autogrouptype;
 
        int center_pixel;
        double view_start, unit_start;
@@ -3380,6 +3477,31 @@ int TrackCanvas::draw_hairline(Auto *auto_keyframe, int color)
 
        set_color(color);
        draw_line(ax, 0, ax, get_h());
+
+       if( show ) {
+               char text[BCSTRLEN];
+               if( auto_keyframe->is_floatauto() ) {
+                       FloatAuto *float_auto = (FloatAuto *)auto_keyframe;
+                       sprintf(text, "%0.2f", float_auto->get_value());
+               }
+               else {
+                       IntAuto *int_auto = (IntAuto *)auto_keyframe;
+                       sprintf(text, "%d", int_auto->value);
+               }
+               int font = MEDIUMFONT;
+               int tw = get_text_width(font, text)  + TOOLTIP_MARGIN * 2;
+               int th = get_text_height(font, text) + TOOLTIP_MARGIN * 2;
+               set_color(get_resources()->tooltip_bg_color);
+               ax += HANDLE_W/2;
+               ay += center_pixel + HANDLE_W/2;
+               draw_box(ax, ay, tw, th);
+               set_color(BLACK);
+               draw_rectangle(ax, ay, tw, th);
+               set_font(font);
+               ax += TOOLTIP_MARGIN;
+               ay += TOOLTIP_MARGIN + get_text_ascent(font);
+               draw_text(ax, ay, text);
+       }
        return 0;
 }
 
@@ -3400,14 +3522,15 @@ void TrackCanvas::draw_overlays()
        draw_inout_points();
 
 // Transitions
-       if(mwindow->edl->session->auto_conf->transitions) draw_transitions();
+       draw_transitions();
 
 // Plugins
        draw_plugins();
+       draw_hard_edges();
 
 // Loop points
        draw_loop_points();
-       draw_brender_start();
+       draw_brender_range();
 
 // Highlighted areas
        draw_highlighting();
@@ -3458,30 +3581,134 @@ int TrackCanvas::deactivate()
 void TrackCanvas::update_drag_handle()
 {
        double new_position;
+       int cursor_x = get_cursor_x();
 
        new_position =
-               (double)(get_cursor_x() +
+               (double)(cursor_x +
                mwindow->edl->local_session->view_start[pane->number]) *
                mwindow->edl->local_session->zoom_sample /
                mwindow->edl->session->sample_rate;
+
        new_position =
                mwindow->edl->align_to_frame(new_position, 0);
 
+       if( ctrl_down() && alt_down() ) {
+#define snapper(v) do { \
+       double pos = (v); \
+       if( pos < 0 ) break; \
+       double dist = fabs(new_position - pos); \
+       if( dist >= snap_min ) break; \
+       snap_position = pos;  snap_min = dist; \
+} while(0)
+               double snap_position = new_position;
+               double snap_min = DBL_MAX;
+               if( mwindow->edl->local_session->inpoint_valid() )
+                       snapper(mwindow->edl->local_session->get_inpoint());
+               if( mwindow->edl->local_session->outpoint_valid() )
+                       snapper(mwindow->edl->local_session->get_outpoint());
+               snapper(mwindow->edl->prev_edit(new_position));
+               snapper(mwindow->edl->next_edit(new_position));
+               Label *prev_label = mwindow->edl->labels->prev_label(new_position);
+               if( prev_label ) snapper(prev_label->position);
+               Label *next_label = mwindow->edl->labels->next_label(new_position);
+               if( next_label ) snapper(next_label->position);
+               int snap_x = snap_position * mwindow->edl->session->sample_rate /
+                       mwindow->edl->local_session->zoom_sample -
+                       mwindow->edl->local_session->view_start[pane->number];
+               if( abs(snap_x - cursor_x) < HANDLE_W ) {
+                       snapped = 1;
+                       new_position = snap_position;
+               }
+#undef snapper
+       }
 
        if(new_position != mwindow->session->drag_position)
        {
                mwindow->session->drag_position = new_position;
                gui->mainclock->update(new_position);
-
-
                timebar_position = new_position;
                gui->update_timebar(0);
-// Que the CWindow.  Doesn't do anything if selectionstart and selection end
-// aren't changed.
-//             mwindow->cwindow->update(1, 0, 0);
+
+               EDL *edl = new EDL;
+               edl->create_objects();
+               edl->copy_all(mwindow->edl);
+               MainSession *session = mwindow->session;
+               int edit_mode = mwindow->edl->session->edit_handle_mode[session->drag_button];
+               edl->modify_edithandles(session->drag_start,
+                       session->drag_position,
+                       session->drag_handle,
+                       edit_mode,
+                       edl->session->labels_follow_edits,
+                       edl->session->plugins_follow_edits,
+                       edl->session->autos_follow_edits);
+               double position = edit_mode != MOVE_NO_EDITS &&
+                       ( session->drag_handle || edit_mode == MOVE_ONE_EDIT ) ?
+                               session->drag_position : session->drag_start;
+               Track *track = session->drag_handle_track();
+               int64_t pos = track->to_units(position, 0);
+               render_handle_frame(edl, pos, shift_down() ? 0 :
+                       session->drag_handle ? 1 : 2);
+               edl->remove_user();
        }
 }
 
+int TrackCanvas::render_handle_frame(EDL *edl, int64_t pos, int mode)
+{
+       int result = 0;
+       int64_t left = pos-1;
+       if( left < 0 ) left = 0;
+       switch( mode ) {
+       case 0: {
+               VFrame vlt(edl->get_w(), edl->get_h(), edl->session->color_model);
+               VFrame vrt(edl->get_w(), edl->get_h(), edl->session->color_model);
+               TransportCommand command;
+               command.command = CURRENT_FRAME;
+               command.get_edl()->copy_all((EDL *)edl);
+               command.change_type = CHANGE_ALL;
+               command.realtime = 0;
+               Preferences *preferences = mwindow->preferences;
+               RenderEngine *render_engine = new RenderEngine(0, preferences, 0, 0);
+               CICache *video_cache = new CICache(preferences);
+               render_engine->set_vcache(video_cache);
+               render_engine->arm_command(&command);
+               int64_t left = pos-1;
+               if( left < 0 ) left = 0;
+               VRender *vrender = render_engine->vrender;
+               result = vrender &&
+                       !vrender->process_buffer(&vlt, left, 0) &&
+                       !vrender->process_buffer(&vrt, pos , 0) ? 0 : 1;
+               delete render_engine;
+               delete video_cache;
+               mwindow->cwindow->gui->lock_window("TrackCanvas::render_handle_frame 0");
+               Canvas *canvas = mwindow->cwindow->gui->canvas;
+               canvas->lock_canvas("TrackCanvas::render_handle_frame 1");
+               int w = canvas->w, h = canvas->h, w2 = w/2, h2 = h/2;
+               int lx = 0, ly = h2/2, rx = w2, ry = h2/2;
+               BC_WindowBase *window = canvas->get_canvas();
+               window->set_color(BLACK);
+               window->clear_box(0,0, window->get_w(),window->get_h());
+               window->draw_vframe(&vlt, lx,ly, w2,h2, 0,0,vlt.get_w(),vlt.get_h());
+               window->draw_vframe(&vrt, rx,ry, w2,h2, 0,0,vrt.get_w(),vrt.get_h());
+               window->flash(1);
+               canvas->unlock_canvas();
+               mwindow->cwindow->gui->unlock_window();
+               break; }
+       case 1:
+       case 2: {
+               Track *track = mwindow->session->drag_handle_track();
+               double position = track->from_units(mode == 1 ? left : pos);
+               if( position < 0 ) position = 0;
+               edl->local_session->set_selectionstart(position);
+               edl->local_session->set_selectionend(position);
+               PlaybackEngine *playback_engine = mwindow->cwindow->playback_engine;
+               if( playback_engine->is_playing_back )
+                       playback_engine->stop_playback(1);
+               mwindow->cwindow->playback_engine->refresh_frame(CHANGE_EDL, edl, 0);
+               break; }
+       }
+       return result;
+}
+
 int TrackCanvas::update_drag_edit()
 {
        int result = 0;
@@ -3570,7 +3797,7 @@ int TrackCanvas::update_drag_floatauto(int cursor_x, int cursor_y)
 // 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) &&                                          
+                    FloatAuto::TFREE==current->curve_mode) &&
                    (fabs(x) > HANDLE_W / 2 || fabs(y) > HANDLE_W / 2))
                        mwindow->session->drag_handle = x < 0 ? 1 : 2;
        }
@@ -3616,9 +3843,9 @@ int TrackCanvas::update_drag_floatauto(int cursor_x, int cursor_y)
 
                if(value != old_value || position != current->position) {
                        result = 1;
-                       float change = value - old_value;               
+                       float change = value - old_value;
                        current->adjust_to_new_coordinates(position, value);
-                       synchronize_autos(change, current->autos->track, current, 0);
+                       update_ganged_autos(change, current->autos->track, current);
                        show_message(current, 1,", %.2f", current->get_value());
                }
                break;
@@ -3637,7 +3864,7 @@ int TrackCanvas::update_drag_floatauto(int cursor_x, int cursor_y)
                        current->set_control_in_value(
                                value * levered_position(position - current->position,
                                                         current->get_control_in_position()));
-                       synchronize_autos(0, current->autos->track, current, 0);
+                       update_ganged_autos(0, current->autos->track, current);
                        show_message(current, 1,", %.2f", current->get_control_in_value());
                }
                break; }
@@ -3651,7 +3878,7 @@ int TrackCanvas::update_drag_floatauto(int cursor_x, int cursor_y)
                        current->set_control_out_value(
                                value * levered_position(position - current->position,
                                                         current->get_control_out_position()));
-                       synchronize_autos(0, current->autos->track, current, 0);
+                       update_ganged_autos(0, current->autos->track, current);
                        show_message(current, 1,", %.2f", current->get_control_out_value());
                }
                break; }
@@ -3693,7 +3920,7 @@ int TrackCanvas::update_drag_auto(int cursor_x, int cursor_y)
 
                double position_f = current->autos->track->from_units(current->position);
                double center_f = (mwindow->edl->local_session->get_selectionstart(1) +
-                       mwindow->edl->local_session->get_selectionend(1)) / 
+                       mwindow->edl->local_session->get_selectionend(1)) /
                        2;
                if(!shift_down())
                {
@@ -3725,7 +3952,7 @@ int TrackCanvas::update_drag_pluginauto(int cursor_x, int cursor_y)
                //PluginAutos *pluginautos = (PluginAutos *)current->autos;
                PluginSet *pluginset;
                Plugin *plugin = 0;
-// figure out the correct pluginset & correct plugin 
+// figure out the correct pluginset & correct plugin
                int found = 0;
                for(int i = 0; i < track->plugin_set.total; i++)
                {
@@ -3737,16 +3964,16 @@ int TrackCanvas::update_drag_pluginauto(int cursor_x, int cursor_y)
                                        currentkeyframe;
                                        currentkeyframe = (KeyFrame *) currentkeyframe->next)
                                {
-                                       if (currentkeyframe == current) 
+                                       if (currentkeyframe == current)
                                        {
                                                found = 1;
                                                break;
                                        }
+
                                }
-                               if (found) break;                       
+                               if (found) break;
                        }
-                       if (found) break;                       
+                       if (found) break;
                }
 
                mwindow->session->plugin_highlighted = plugin;
@@ -3757,7 +3984,7 @@ int TrackCanvas::update_drag_pluginauto(int cursor_x, int cursor_y)
 
                double position_f = current->autos->track->from_units(current->position);
                double center_f = (mwindow->edl->local_session->get_selectionstart(1) +
-                       mwindow->edl->local_session->get_selectionend(1)) / 
+                       mwindow->edl->local_session->get_selectionend(1)) /
                        2;
                if(!shift_down())
                {
@@ -3782,14 +4009,14 @@ void TrackCanvas::update_drag_caption()
        switch(mwindow->session->current_operation)
        {
                case DRAG_FADE:
-                       
+
                        break;
        }
 }
 
 
 
-int TrackCanvas::cursor_motion_event()
+int TrackCanvas::cursor_update(int in_motion)
 {
        int result = 0;
        int cursor_x = 0;
@@ -3802,7 +4029,7 @@ int TrackCanvas::cursor_motion_event()
        int new_cursor = 0;
        int rerender = 0;
        double position = 0.;
-//printf("TrackCanvas::cursor_motion_event %d\n", __LINE__);
+//printf("TrackCanvas::cursor_update %d\n", __LINE__);
 
 // Default cursor
        switch(mwindow->edl->session->editing_mode)
@@ -3865,6 +4092,8 @@ int TrackCanvas::cursor_motion_event()
                case DRAG_PROJECTOR_Z:
                        if(active) rerender = update_overlay =
                                update_drag_floatauto(get_cursor_x(), get_cursor_y());
+                       if( rerender && mwindow->session->current_operation == DRAG_SPEED )
+                               mwindow->speed_after(!in_motion ? 1 : 0);
                        break;
 
                case DRAG_PLAY:
@@ -3914,22 +4143,26 @@ int TrackCanvas::cursor_motion_event()
                                position = mwindow->edl->align_to_frame(position, 0);
                                position = MAX(position, 0);
 
+                               double start = mwindow->edl->local_session->get_selectionstart(1);
+                               double end = mwindow->edl->local_session->get_selectionend(1);
                                if(position < selection_midpoint) {
                                        mwindow->edl->local_session->set_selectionend(selection_midpoint);
                                        mwindow->edl->local_session->set_selectionstart(position);
-       // Que the CWindow
-                                       gui->unlock_window();
-                                       mwindow->cwindow->update(1, 0, 0, 0, 1);
-                                       gui->lock_window("TrackCanvas::cursor_motion_event 1");
-       // Update the faders
-                                       mwindow->update_plugin_guis();
-                                       gui->update_patchbay();
                                }
                                else {
                                        mwindow->edl->local_session->set_selectionstart(selection_midpoint);
                                        mwindow->edl->local_session->set_selectionend(position);
-       // Don't que the CWindow
                                }
+       // Que the CWindow
+                               gui->unlock_window();
+                               int dir =
+                                       start != mwindow->edl->local_session->get_selectionstart(1) ? 1 :
+                                       end != mwindow->edl->local_session->get_selectionend(1) ? -1 : 0;
+                               mwindow->cwindow->update(dir, 0, 0, 0, 1);
+                               gui->lock_window("TrackCanvas::cursor_update 1");
+       // Update the faders
+                               mwindow->update_plugin_guis();
+                               gui->update_patchbay();
 
                                timebar_position = mwindow->edl->local_session->get_selectionend(1);
 
@@ -3961,7 +4194,7 @@ int TrackCanvas::cursor_motion_event()
                                for(int i = 0; i < TOTAL_PANES; i++)
                                        if(gui->pane[i]) gui->pane[i]->canvas->timebar_position = position;
 
-//printf("TrackCanvas::cursor_motion_event %d %d %p %p\n", __LINE__, pane->number, pane, pane->timebar);
+//printf("TrackCanvas::cursor_update %d %d %p %p\n", __LINE__, pane->number, pane, pane->timebar);
                                gui->update_timebar(0);
 // Update cursor
                                if(do_transitions(get_cursor_x(), get_cursor_y(),
@@ -3979,13 +4212,13 @@ int TrackCanvas::cursor_motion_event()
                        break;
        }
 
-//printf("TrackCanvas::cursor_motion_event 1\n");
+//printf("TrackCanvas::cursor_update 1\n");
        if(update_cursor && new_cursor != get_cursor())
        {
                set_cursor(new_cursor, 0, 1);
        }
 
-//printf("TrackCanvas::cursor_motion_event 1 %d\n", rerender);
+//printf("TrackCanvas::cursor_update 1 %d\n", rerender);
        if(rerender && render_timer->get_difference() > 0.25 ) {
                render_timer->update();
                mwindow->restart_brender();
@@ -3993,7 +4226,7 @@ int TrackCanvas::cursor_motion_event()
                mwindow->update_plugin_guis();
                gui->unlock_window();
                mwindow->cwindow->update(1, 0, 0, 0, 1);
-               gui->lock_window("TrackCanvas::cursor_motion_event 2");
+               gui->lock_window("TrackCanvas::cursor_update 2");
        }
        if(rerender) {
 // Update faders
@@ -4024,10 +4257,15 @@ int TrackCanvas::cursor_motion_event()
                gui->draw_overlays(1);
        }
 
-//printf("TrackCanvas::cursor_motion_event %d\n", __LINE__);
+//printf("TrackCanvas::cursor_update %d\n", __LINE__);
        return result;
 }
 
+int TrackCanvas::cursor_motion_event()
+{
+       return cursor_update(1);
+}
+
 void TrackCanvas::start_dragscroll()
 {
        if(!drag_scroll) {
@@ -4127,7 +4365,8 @@ int TrackCanvas::repeat_event(int64_t duration)
 
 int TrackCanvas::button_release_event()
 {
-       int redraw = 0, update_overlay = 0, result = 0;
+       int redraw = -1, update_overlay = 0;
+       int result = 0, load_flags = 0;
 
 // printf("TrackCanvas::button_release_event %d\n",
 // mwindow->session->current_operation);
@@ -4161,10 +4400,12 @@ int TrackCanvas::button_release_event()
                        result = 1;
                        break;
 
-               case DRAG_FADE:
                case DRAG_SPEED:
+                       redraw = FORCE_REDRAW;
+                       load_flags |= LOAD_EDITS;
+               case DRAG_FADE:
 // delete the drag_auto_gang first and remove out of order keys
-                       synchronize_autos(0, 0, 0, -1);
+                       clear_ganged_autos();
                case DRAG_CZOOM:
                case DRAG_PZOOM:
                case DRAG_PLAY:
@@ -4179,6 +4420,7 @@ int TrackCanvas::button_release_event()
                case DRAG_PROJECTOR_Y:
                case DRAG_PROJECTOR_Z:
                case DRAG_PLUGINKEY:
+                       load_flags |= LOAD_AUTOMATION;
                        mwindow->session->current_operation = NO_OPERATION;
                        mwindow->session->drag_handle = 0;
 // Remove any out-of-order keyframe
@@ -4189,8 +4431,7 @@ int TrackCanvas::button_release_event()
                                update_overlay = 1;
                        }
 
-
-                       mwindow->undo->update_undo_after(_("keyframe"), LOAD_AUTOMATION);
+                       mwindow->undo->update_undo_after(_("keyframe"), load_flags);
                        result = 1;
                        break;
 
@@ -4217,13 +4458,14 @@ int TrackCanvas::button_release_event()
        }
 
        if (result)
-               cursor_motion_event();
+               cursor_update(0);
 
        if(update_overlay) {
                gui->draw_overlays(1);
        }
-       if(redraw) {
-               gui->draw_canvas(NORMAL_DRAW, 0);
+       if(redraw >= 0) {
+               gui->draw_canvas(redraw, 0);
+               gui->flash_canvas(1);
        }
        return result;
 }
@@ -4232,53 +4474,58 @@ int TrackCanvas::do_edit_handles(int cursor_x, int cursor_y, int button_press,
        int &rerender, int &update_overlay, int &new_cursor, int &update_cursor)
 {
        Edit *edit_result = 0;
-       int handle_result = 0;
+       int handle_result = -1;
        int result = 0;
 
-       if(!mwindow->edl->session->show_assets) return 0;
-
-       for(Track *track = mwindow->edl->tracks->first;
-               track && !result;
-               track = track->next) {
-               for(Edit *edit = track->edits->first;
-                       edit && !result;
-                       edit = edit->next) {
+       for( Track *track=mwindow->edl->tracks->first; track && !result; track=track->next) {
+               for( Edit *edit=track->edits->first; edit && !result; edit=edit->next ) {
                        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_x <= edit_x + edit_w &&
-                               cursor_y >= edit_y && cursor_y < edit_y + edit_h) {
-                               if(cursor_x < edit_x + HANDLE_W) {
+                       if( cursor_x >= edit_x && cursor_x <= edit_x + edit_w &&
+                               cursor_y >= edit_y && cursor_y < edit_y + edit_h ) {
+                               if( cursor_x < edit_x + HANDLE_W ) {
                                        edit_result = edit;
                                        handle_result = 0;
-                                       result = 1;
+                                       if( cursor_y >= edit_y+edit_h - HANDLE_W &&
+                                           track->show_assets() ) {
+                                               new_cursor = DOWNLEFT_RESIZE;
+                                               if( button_press == LEFT_BUTTON )
+                                                       result = -1;
+                                       }
+                                       else
+                                               result = 1;
                                }
-                               else if(cursor_x >= edit_x + edit_w - HANDLE_W) {
+                               else if( cursor_x >= edit_x + edit_w - HANDLE_W ) {
                                        edit_result = edit;
                                        handle_result = 1;
-                                       result = 1;
-                               }
-                               else {
-                                       result = 0;
+                                       if( cursor_y >= edit_y+edit_h - HANDLE_W &&
+                                           track->show_assets() ) {
+                                               new_cursor = DOWNRIGHT_RESIZE;
+                                               if( button_press == LEFT_BUTTON )
+                                                       result = -1;
+                                       }
+                                       else
+                                               result = 1;
                                }
                        }
                }
        }
 
        update_cursor = 1;
-       if(result) {
+       if( result > 0 ) {
                double position = 0;
-               if(handle_result == 0) {
+               if( handle_result == 0 ) {
                        position = edit_result->track->from_units(edit_result->startproject);
                        new_cursor = LEFT_CURSOR;
                }
-               else if(handle_result == 1) {
+               else if( handle_result == 1 ) {
                        position = edit_result->track->from_units(edit_result->startproject + edit_result->length);
                        new_cursor = RIGHT_CURSOR;
                }
 
 // Reposition cursor
-               if(button_press) {
+               if( button_press ) {
                        mwindow->session->drag_edit = edit_result;
                        mwindow->session->drag_handle = handle_result;
                        mwindow->session->drag_button = get_buttonpress() - 1;
@@ -4292,6 +4539,49 @@ int TrackCanvas::do_edit_handles(int cursor_x, int cursor_y, int button_press,
                        update_overlay = 1;
                }
        }
+       else if( result < 0 ) {
+               mwindow->undo->update_undo_before();
+               if( !shift_down() ) {
+                       if( handle_result == 0 )
+                               edit_result->hard_left = !edit_result->hard_left;
+                       else if( handle_result == 1 )
+                               edit_result->hard_right = !edit_result->hard_right;
+               }
+               else {
+                       int status = handle_result == 0 ? edit_result->hard_left :
+                                    handle_result == 1 ? edit_result->hard_right : 0;
+                       int new_status = !status;
+                       int64_t edit_edge = edit_result->startproject;
+                       if( handle_result == 1 ) edit_edge += edit_result->length;
+                       double edge_position = edit_result->track->from_units(edit_edge);
+                       for( Track *track=mwindow->edl->tracks->first; track!=0; track=track->next ) {
+                               int64_t track_position = track->to_units(edge_position, 1);
+                               Edit *left_edit = track->edits->editof(track_position, PLAY_FORWARD, 0);
+                               if( left_edit ) {
+                                       int64_t left_edge = left_edit->startproject;
+                                       double left_position = track->from_units(left_edge);
+                                       if( EQUIV(edge_position, left_position) ) {
+                                               left_edit->hard_left = new_status;
+                                               if( left_edit->previous )
+                                                       left_edit->previous->hard_right = new_status;
+                                       }
+                               }
+                               Edit *right_edit = track->edits->editof(track_position, PLAY_REVERSE, 0);
+                               if( right_edit ) {
+                                       int64_t right_edge = right_edit->startproject + right_edit->length;
+                                       double right_position = track->from_units(right_edge);
+                                       if( EQUIV(edge_position, right_position) ) {
+                                               right_edit->hard_right = new_status;
+                                               if( right_edit->next )
+                                                       right_edit->next->hard_left = new_status;
+                                       }
+                               }
+                       }
+               }
+               rerender = update_overlay = 1;
+               mwindow->undo->update_undo_after(_("hard_edge"), LOAD_EDITS);
+               result = 1;
+       }
 
        return result;
 }
@@ -4308,8 +4598,6 @@ int TrackCanvas::do_plugin_handles(int cursor_x,
        int handle_result = 0;
        int result = 0;
 
-//     if(!mwindow->edl->session->show_assets) return 0;
-
        for(Track *track = mwindow->edl->tracks->first;
                track && !result;
                track = track->next) {
@@ -4376,17 +4664,17 @@ int TrackCanvas::do_tracks(int cursor_x, int cursor_y, int button_press)
 {
        int result = 0;
 
-//     if(!mwindow->edl->session->show_assets) return 0;
-
        for(Track *track = mwindow->edl->tracks->first;
                track && !result;
                track = track->next) {
                int64_t track_x, track_y, track_w, track_h;
                track_dimensions(track, track_x, track_y, track_w, track_h);
 
-               if(button_press && get_buttonpress() == 3 &&
-                       cursor_y >= track_y && cursor_y < track_y + track_h) {
-                       gui->edit_menu->update(track, 0);
+               if( button_press && get_buttonpress() == RIGHT_BUTTON &&
+                   cursor_y >= track_y && cursor_y < track_y + track_h) {
+                       double pos = mwindow->edl->get_cursor_position(cursor_x, pane->number);
+                       int64_t position = track->to_units(pos, 0);
+                       gui->edit_menu->update(track, track->edits->editof(position, PLAY_FORWARD, 0));
                        gui->edit_menu->activate_menu();
                        result = 1;
                }
@@ -4400,10 +4688,7 @@ int TrackCanvas::do_edits(int cursor_x, int cursor_y, int button_press, int drag
 {
        int result = 0;
 
-       if(!mwindow->edl->session->show_assets) return 0;
-
        for(Track *track = mwindow->edl->tracks->first; track && !result; track = track->next) {
-
                for(Edit *edit = track->edits->first; edit && !result; edit = edit->next) {
                        int64_t edit_x, edit_y, edit_w, edit_h;
                        edit_dimensions(edit, edit_x, edit_y, edit_w, edit_h);
@@ -4460,10 +4745,10 @@ int TrackCanvas::do_edits(int cursor_x, int cursor_y, int button_press, int drag
                                                        mwindow->edl->local_session->zoom_sample /
                                                        mwindow->edl->session->sample_rate;
 
+                                               int cx, cy;
+                                               get_abs_cursor(cx, cy);
                                                gui->drag_popup = new BC_DragWindow(gui,
-                                                       mwindow->theme->get_image("clip_icon") /*,
-                                                       get_abs_cursor_x(0) - mwindow->theme->get_image("clip_icon")->get_w() / 2,
-                                                       get_abs_cursor_y(0) - mwindow->theme->get_image("clip_icon")->get_h() / 2 */);
+                                                       mwindow->theme->get_image("clip_icon"), cx, cy);
 
                                                result = 1;
                                        }
@@ -4489,10 +4774,6 @@ int TrackCanvas::do_plugins(int cursor_x, int cursor_y, int drag_start,
        int64_t x, y, w, h;
        Track *track = 0;
 
-
-//     if(!mwindow->edl->session->show_assets) return 0;
-
-
        for(track = mwindow->edl->tracks->first; track && !done; track = track->next) {
                if(!track->expand_view) continue;
 
@@ -4572,19 +4853,18 @@ int TrackCanvas::do_plugins(int cursor_x, int cursor_y, int drag_start,
                                                        frame = mwindow->theme->get_image("veffect_icon");
                                                }
                                        }
-
-                                       gui->drag_popup = new BC_DragWindow(gui, frame /*,
-                                               get_abs_cursor_x(0) - frame->get_w() / 2,
-                                               get_abs_cursor_y(0) - frame->get_h() / 2 */);
+                                       int cx, cy;
+                                       get_abs_cursor(cx, cy);
+                                       gui->drag_popup = new BC_DragWindow(gui, frame, cx, cy);
                                                break; }
 
                                case PLUGIN_SHAREDPLUGIN:
-                               case PLUGIN_SHAREDMODULE:
-                                       gui->drag_popup = new BC_DragWindow(gui,
-                                               mwindow->theme->get_image("clip_icon") /*,
-                                               get_abs_cursor_x(0) - mwindow->theme->get_image("clip_icon")->get_w() / 2,
-                                               get_abs_cursor_y(0) - mwindow->theme->get_image("clip_icon")->get_h() / 2 */);
-                                       break;
+                               case PLUGIN_SHAREDMODULE: {
+                                       VFrame *frame = mwindow->theme->get_image("clip_icon");
+                                       int cx, cy;
+                                       get_abs_cursor(cx, cy);
+                                       gui->drag_popup = new BC_DragWindow(gui, frame, cx, cy);
+                                       break; }
                                }
 
                                result = 1;
@@ -4602,15 +4882,14 @@ int TrackCanvas::do_transitions(int cursor_x, int cursor_y,
        int result = 0;
        int64_t x, y, w, h;
 
-       if(/* !mwindow->edl->session->show_assets || */
-               !mwindow->edl->session->auto_conf->transitions) return 0;
 
        for( Track *track = mwindow->edl->tracks->first; track && !result; track = track->next ) {
+               if( !track->show_transitions() ) continue;
 
                for( Edit *edit = track->edits->first; edit; edit = edit->next ) {
                        if( edit->transition ) {
                                edit_dimensions(edit, x, y, w, h);
-                               get_transition_coords(x, y, w, h);
+                               get_transition_coords(edit, x, y, w, h);
 
                                if( MWindowGUI::visible(x, x + w, 0, get_w()) &&
                                        MWindowGUI::visible(y, y + h, 0, get_h()) ) {
@@ -4650,12 +4929,7 @@ int TrackCanvas::button_press_event()
        mwindow->session->trim_edits = 0;
 
        if(is_event_win() && cursor_inside()) {
-//             double position = (double)cursor_x *
-//                     mwindow->edl->local_session->zoom_sample /
-//                     mwindow->edl->session->sample_rate +
-//                     (double)mwindow->edl->local_session->view_start[pane->number] *
-//                     mwindow->edl->local_session->zoom_sample /
-//                     mwindow->edl->session->sample_rate;
+//             double position = mwindow->edl->get_cursor_position(cursor_x, pane->number);
 
                result = 1;
                if(!active) {
@@ -4663,9 +4937,7 @@ int TrackCanvas::button_press_event()
                }
 
                if( get_buttonpress() == LEFT_BUTTON ) {
-                       gui->unlock_window();
-                       gui->mbuttons->transport->handle_transport(STOP, 1, 0, 0);
-                       gui->lock_window("TrackCanvas::button_press_event");
+                       gui->stop_transport("TrackCanvas::button_press_event");
                }
 
                int update_overlay = 0, update_cursor = 0, rerender = 0;
@@ -4737,12 +5009,7 @@ int TrackCanvas::button_press_event()
 
 // Test handles only and select a region
                        case EDITING_IBEAM: {
-                               double position = (double)cursor_x *
-                                       mwindow->edl->local_session->zoom_sample /
-                                       mwindow->edl->session->sample_rate +
-                                       (double)mwindow->edl->local_session->view_start[pane->number] *
-                                       mwindow->edl->local_session->zoom_sample /
-                                       mwindow->edl->session->sample_rate;
+                               double position = mwindow->edl->get_cursor_position(cursor_x, pane->number);
 //printf("TrackCanvas::button_press_event %d\n", position);
 
                                if( do_transitions(cursor_x, cursor_y,
@@ -4799,19 +5066,20 @@ int TrackCanvas::button_press_event()
                        gui->flash_canvas(1);
                }
        }
+
        return result;
 }
 
 int TrackCanvas::start_selection(double position)
 {
        int rerender = 0;
-       position = mwindow->edl->align_to_frame(position, 0);
+       position = mwindow->edl->align_to_frame(position, 1);
 
 
 // Extend a border
        if(shift_down())
        {
-               double midpoint = (mwindow->edl->local_session->get_selectionstart(1) + 
+               double midpoint = (mwindow->edl->local_session->get_selectionstart(1) +
                        mwindow->edl->local_session->get_selectionend(1)) / 2;
 
                if(position < midpoint)
@@ -4838,7 +5106,7 @@ int TrackCanvas::start_selection(double position)
 // Que the CWindow
                rerender = 1;
        }
-       
+
        return rerender;
 }
 
@@ -4855,8 +5123,8 @@ void TrackCanvas::end_pluginhandle_selection()
 
 double TrackCanvas::time_visible()
 {
-       return (double)get_w() * 
-               mwindow->edl->local_session->zoom_sample / 
+       return (double)get_w() *
+               mwindow->edl->local_session->zoom_sample /
                mwindow->edl->session->sample_rate;
 }
 
@@ -4870,7 +5138,7 @@ void TrackCanvas::show_message(Auto *current, int show_curve_type, const char *f
                        FloatAuto::curve_name(((FloatAuto*)current)->curve_mode));
        }
        char string2[BCTEXTLEN];
-       Units::totext(string2, 
+       Units::totext(string2,
                current->autos->track->from_units(current->position),
                mwindow->edl->session->time_format,
                mwindow->edl->session->sample_rate,
@@ -4898,7 +5166,7 @@ void TrackCanvas::show_message(Auto *current, int show_curve_type, const char *f
 //             else
 //                     return gui->pane[BOTTOM_LEFT_PANE]->patchbay;
 //     }
-// 
+//
 //     return 0;
 // }