Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

trackcanvas.C

Go to the documentation of this file.
00001 #include "asset.h"
00002 #include "autoconf.h"
00003 #include "automation.h"
00004 #include "bcsignals.h"
00005 #include "bctimer.h"
00006 #include "clip.h"
00007 #include "colors.h"
00008 #include "cplayback.h"
00009 #include "cursors.h"
00010 #include "cwindow.h"
00011 #include "cwindowgui.h"
00012 #include "edithandles.h"
00013 #include "editpopup.h"
00014 #include "edits.h"
00015 #include "edl.h"
00016 #include "edlsession.h"
00017 #include "floatauto.h"
00018 #include "floatautos.h"
00019 #include "intauto.h"
00020 #include "keyframe.h"
00021 #include "keyframepopup.h"
00022 #include "keyframes.h"
00023 #include "keys.h"
00024 #include "localsession.h"
00025 #include "mainclock.h"
00026 #include "maincursor.h"
00027 #include "mainundo.h"
00028 #include "maskautos.h"
00029 #include "mbuttons.h"
00030 #include "mtimebar.h"
00031 #include "mwindow.h"
00032 #include "mwindowgui.h"
00033 #include "patchbay.h"
00034 #include "tracking.h"
00035 #include "panautos.h"
00036 #include "playbackengine.h"
00037 #include "playtransport.h"
00038 #include "plugin.h"
00039 #include "pluginpopup.h"
00040 #include "pluginset.h"
00041 #include "pluginserver.h"
00042 #include "preferences.h"
00043 #include "resourcepixmap.h"
00044 #include "mainsession.h"
00045 #include "transitionhandles.h"
00046 #include "transitionpopup.h"
00047 #include "transportque.h"
00048 #include "zoombar.h"
00049 #include "theme.h"
00050 #include "intautos.h"
00051 #include "trackcanvas.h"
00052 #include "tracks.h"
00053 #include "transition.h"
00054 #include "vframe.h"
00055 #include "apatchgui.inc"
00056 #include "vpatchgui.inc"
00057 
00058 #include <string.h>
00059 
00060 TrackCanvas::TrackCanvas(MWindow *mwindow, MWindowGUI *gui)
00061  : BC_SubWindow(mwindow->theme->mcanvas_x,
00062         mwindow->theme->mcanvas_y,
00063         gui->view_w,
00064         gui->view_h)
00065 {
00066         this->mwindow = mwindow;
00067         this->gui = gui;
00068         current_end = 0;
00069         selection_midpoint1 = selection_midpoint2 = 0;
00070         selection_type = 0;
00071         region_selected = 0;
00072         handle_selected = 0;
00073         auto_selected = 0;
00074         translate_selected = 0;
00075         which_handle = 0;
00076         handle_pixel = 0;
00077         drag_scroll = 0;
00078         drag_popup = 0;
00079         active = 0;
00080         temp_picon = 0;
00081         resource_timer = new Timer;
00082         hourglass_enabled = 0;
00083 }
00084 
00085 TrackCanvas::~TrackCanvas()
00086 {
00087         for(int i = 0; i < resource_pixmaps.total; i++)
00088                 delete resource_pixmaps.values[i];
00089 //      delete transition_handles;
00090         delete edit_handles;
00091         delete keyframe_pixmap;
00092         delete camerakeyframe_pixmap;
00093         delete modekeyframe_pixmap;
00094         delete pankeyframe_pixmap;
00095         delete projectorkeyframe_pixmap;
00096         delete maskkeyframe_pixmap;
00097         delete background_pixmap;
00098         if(temp_picon) delete temp_picon;
00099         delete resource_timer;
00100 }
00101 
00102 int TrackCanvas::create_objects()
00103 {
00104         background_pixmap = new BC_Pixmap(this, get_w(), get_h());
00105 //      transition_handles = new TransitionHandles(mwindow, this);
00106         edit_handles = new EditHandles(mwindow, this);
00107         keyframe_pixmap = new BC_Pixmap(this, mwindow->theme->keyframe_data, PIXMAP_ALPHA);
00108         camerakeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->camerakeyframe_data, PIXMAP_ALPHA);
00109         modekeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->modekeyframe_data, PIXMAP_ALPHA);
00110         pankeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->pankeyframe_data, PIXMAP_ALPHA);
00111         projectorkeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->projectorkeyframe_data, PIXMAP_ALPHA);
00112         maskkeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->maskkeyframe_data, PIXMAP_ALPHA);
00113         draw();
00114         update_cursor();
00115         flash();
00116         return 0;
00117 }
00118 
00119 void TrackCanvas::resize_event()
00120 {
00121 //printf("TrackCanvas::resize_event 1\n");
00122         draw(0, 0);
00123         flash();
00124 //printf("TrackCanvas::resize_event 2\n");
00125 }
00126 
00127 int TrackCanvas::keypress_event()
00128 {
00129         int result = 0;
00130 
00131 
00132         return result;
00133 }
00134 
00135 int TrackCanvas::drag_motion()
00136 {
00137         int cursor_x = get_relative_cursor_x();
00138         int cursor_y = get_relative_cursor_y();
00139         Track *over_track = 0;
00140         Edit *over_edit = 0;
00141         PluginSet *over_pluginset = 0;
00142         Plugin *over_plugin = 0;
00143         int redraw = 0;
00144 
00145 
00146         if(drag_popup)
00147         {
00148                 drag_popup->cursor_motion_event();
00149         }
00150 
00151 
00152 // there's no point in drawing highlights has until drag operation has been set
00153         if (!mwindow->session->current_operation)
00154                 return 0;
00155 
00156         if(get_cursor_over_window() &&
00157                 cursor_x >= 0 && 
00158                 cursor_y >= 0 && 
00159                 cursor_x < get_w() && 
00160                 cursor_y < get_h())
00161         {
00162 // Find the edit and track the cursor is over
00163                 for(Track *track = mwindow->edl->tracks->first; track; track = track->next)
00164                 {
00165                         int64_t track_x, track_y, track_w, track_h;
00166                         track_dimensions(track, track_x, track_y, track_w, track_h);
00167 
00168                         if(cursor_y >= track_y && 
00169                                 cursor_y < track_y + track_h)
00170                         {
00171                                 over_track = track;
00172                                 for(Edit *edit = track->edits->first; edit; edit = edit->next)
00173                                 {
00174                                         int64_t edit_x, edit_y, edit_w, edit_h;
00175                                         edit_dimensions(edit, edit_x, edit_y, edit_w, edit_h);
00176 
00177                                         if(cursor_x >= edit_x && 
00178                                                 cursor_y >= edit_y && 
00179                                                 cursor_x < edit_x + edit_w && 
00180                                                 cursor_y < edit_y + edit_h)
00181                                         {
00182                                                 over_edit = edit;
00183                                                 break;
00184                                         }
00185                                 }
00186 
00187                                 for(int i = 0; i < track->plugin_set.total; i++)
00188                                 {
00189                                         PluginSet *pluginset = track->plugin_set.values[i];
00190                                         
00191 
00192 
00193                                         for(Plugin *plugin = (Plugin*)pluginset->first;
00194                                                 plugin;
00195                                                 plugin = (Plugin*)plugin->next)
00196                                         {
00197                                                 int64_t plugin_x, plugin_y, plugin_w, plugin_h;
00198                                                 plugin_dimensions(plugin, plugin_x, plugin_y, plugin_w, plugin_h);
00199                                                 
00200                                                 if(cursor_y >= plugin_y &&
00201                                                         cursor_y < plugin_y + plugin_h)
00202                                                 {
00203                                                         over_pluginset = plugin->plugin_set;
00204                                                 
00205                                                         if(cursor_x >= plugin_x &&
00206                                                                 cursor_x < plugin_x + plugin_w)
00207                                                         {
00208                                                                 over_plugin = plugin;
00209                                                                 break;
00210                                                         }
00211                                                 }
00212                                         }
00213                                 }
00214                                 break;
00215                         }
00216                 }
00217         }
00218 
00219         if (!over_track)        // check for pastes from patchbay
00220                 over_track = mwindow->gui->patchbay->is_over_track();
00221 
00222         if(mwindow->session->track_highlighted != over_track) 
00223         {
00224                 mwindow->session->track_highlighted = over_track;
00225                 redraw = 1;
00226         }
00227 
00228         if(mwindow->session->edit_highlighted != over_edit)
00229         {
00230                 mwindow->session->edit_highlighted = over_edit;
00231                 redraw = 1;
00232         }
00233 
00234         if(mwindow->session->pluginset_highlighted != over_pluginset)
00235         {
00236                 mwindow->session->pluginset_highlighted = over_pluginset;
00237                 redraw = 1;
00238         }
00239 
00240         if(mwindow->session->plugin_highlighted != over_plugin)
00241         {
00242                 mwindow->session->plugin_highlighted = over_plugin;
00243                 redraw = 1;
00244         }
00245 
00246         if (mwindow->session->current_operation == DRAG_ASSET ||
00247           mwindow->session->current_operation == DRAG_EDIT)
00248 
00249         {
00250                 redraw = 1;
00251         }
00252 
00253 //printf("TrackCanvas::drag_motion 2 %p\n", mwindow->session->track_highlighted);
00254         if(redraw)
00255         {
00256                 lock_window("TrackCanvas::drag_motion");
00257                 draw_overlays();
00258                 flash();
00259                 unlock_window();
00260         }
00261 
00262         return 0;
00263 }
00264 
00265 int TrackCanvas::drag_start_event()
00266 {
00267         int result = 0;
00268         int redraw = 0;
00269         int rerender = 0;
00270         int new_cursor, update_cursor;
00271 
00272         if(mwindow->session->current_operation != NO_OPERATION) return 0;
00273 
00274         if(is_event_win())
00275         {
00276                 if(do_plugins(get_drag_x(), 
00277                         get_drag_y(), 
00278                         1,
00279                         0,
00280                         redraw,
00281                         rerender))
00282                 {
00283                         result = 1;
00284                 }
00285                 else
00286                 if(do_edits(get_drag_x(),
00287                         get_drag_y(),
00288                         0,
00289                         1,
00290                         redraw,
00291                         rerender,
00292                         new_cursor,
00293                         update_cursor))
00294                 {
00295                         result = 1;
00296                 }
00297         }
00298 
00299         return result;
00300 }
00301 
00302 int TrackCanvas::drag_motion_event()
00303 {
00304         return drag_motion();
00305 }
00306 
00307 int TrackCanvas::cursor_leave_event()
00308 {
00309 // Because drag motion calls get_cursor_over_window we can be sure that
00310 // all highlights get deleted now.
00311 // This ended up blocking keyboard input from the drag operations.
00312         return 0;
00313 //      return drag_motion();
00314 }
00315 
00316 
00317 int TrackCanvas::drag_stop_event()
00318 {
00319         int result = drag_stop();
00320 
00321         if(drag_popup)
00322         {
00323                 delete drag_popup;
00324                 drag_popup = 0;
00325         }
00326         return result;
00327 }
00328 
00329 
00330 int TrackCanvas::drag_stop()
00331 {
00332 // In most cases the editing routine redraws and not the drag_stop
00333         int result = 0, redraw = 0;
00334 
00335         int insertion = 0;           // used in drag and drop mode
00336         switch(mwindow->session->current_operation)
00337         {
00338                 case DRAG_VTRANSITION:
00339                 case DRAG_ATRANSITION:
00340                         if(mwindow->session->edit_highlighted)
00341                         {
00342                                 if((mwindow->session->current_operation == DRAG_ATRANSITION &&
00343                                         mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
00344                                         (mwindow->session->current_operation == DRAG_VTRANSITION &&
00345                                         mwindow->session->track_highlighted->data_type == TRACK_VIDEO))
00346                                 {
00347                                         mwindow->session->current_operation = NO_OPERATION;
00348                                         mwindow->paste_transition();
00349                                         result = 1;
00350                                 }
00351                         }
00352                         redraw = 1;
00353                         break;
00354 
00355 
00356 
00357 
00358 // Behavior for dragged plugins is limited by the fact that a shared plugin
00359 // can only refer to a standalone plugin that exists in the same position in
00360 // time.  Dragging a plugin from one point in time to another can't produce
00361 // a shared plugin to the original plugin.  In this case we relocate the
00362 // plugin instead of sharing it.
00363                 case DRAG_AEFFECT_COPY:
00364                 case DRAG_VEFFECT_COPY:
00365                         if(mwindow->session->track_highlighted &&
00366                                 ((mwindow->session->current_operation == DRAG_AEFFECT_COPY &&
00367                                         mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
00368                                         (mwindow->session->current_operation == DRAG_VEFFECT_COPY &&
00369                                         mwindow->session->track_highlighted->data_type == TRACK_VIDEO)))
00370                         {
00371                                 mwindow->session->current_operation = NO_OPERATION;
00372 
00373 // Insert shared plugin in source
00374                                 if(mwindow->session->track_highlighted != mwindow->session->drag_plugin->track &&
00375                                         !mwindow->session->plugin_highlighted &&
00376                                         !mwindow->session->pluginset_highlighted)
00377                                 {
00378 // Move plugin if different startproject
00379                                         mwindow->move_effect(mwindow->session->drag_plugin,
00380                                                 0,
00381                                                 mwindow->session->track_highlighted,
00382                                                 0);
00383                                         result = 1;
00384                                 }
00385                                 else
00386 // Move source to different location
00387                                 if(mwindow->session->pluginset_highlighted)
00388                                 {
00389 //printf("TrackCanvas::drag_stop 6\n");
00390                                         if(mwindow->session->plugin_highlighted)
00391                                         {
00392                                                 mwindow->move_effect(mwindow->session->drag_plugin,
00393                                                         mwindow->session->plugin_highlighted->plugin_set,
00394                                                         0,
00395                                                         mwindow->session->plugin_highlighted->startproject);
00396                                         }
00397                                         else
00398                                         {
00399                                                 mwindow->move_effect(mwindow->session->drag_plugin,
00400                                                         mwindow->session->pluginset_highlighted,
00401                                                         0,
00402                                                         mwindow->session->pluginset_highlighted->length());
00403                                         }
00404                                         result = 1;
00405                                 }
00406                                 else
00407 // Move to a new plugin set between two edits
00408                                 if(mwindow->session->edit_highlighted)
00409                                 {
00410                                         mwindow->move_effect(mwindow->session->drag_plugin,
00411                                                 0,
00412                                                 mwindow->session->track_highlighted,
00413                                                 mwindow->session->edit_highlighted->startproject);
00414                                         result = 1;
00415                                 }
00416                                 else
00417 // Move to a new plugin set
00418                                 if(mwindow->session->track_highlighted)
00419                                 {
00420                                         mwindow->move_effect(mwindow->session->drag_plugin,
00421                                                 0,
00422                                                 mwindow->session->track_highlighted,
00423                                                 0);
00424                                         result = 1;
00425                                 }
00426                         }
00427                         break;
00428 
00429                 case DRAG_AEFFECT:
00430                 case DRAG_VEFFECT:
00431                         if(mwindow->session->track_highlighted && 
00432                                 ((mwindow->session->current_operation == DRAG_AEFFECT &&
00433                                 mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
00434                                 (mwindow->session->current_operation == DRAG_VEFFECT &&
00435                                 mwindow->session->track_highlighted->data_type == TRACK_VIDEO)))
00436                         {
00437 // Drop all the effects
00438                                 PluginSet *plugin_set = mwindow->session->pluginset_highlighted;
00439                                 Track *track = mwindow->session->track_highlighted;
00440                                 double start = 0;
00441                                 double length = track->get_length();
00442 
00443                                 if(mwindow->session->plugin_highlighted)
00444                                 {
00445                                         start = track->from_units(mwindow->session->plugin_highlighted->startproject);
00446                                         length = track->from_units(mwindow->session->plugin_highlighted->length);
00447                                         if(length <= 0) length = track->get_length();
00448                                 }
00449                                 else
00450                                 if(mwindow->session->pluginset_highlighted)
00451                                 {
00452                                         start = track->from_units(plugin_set->length());
00453                                         length = track->get_length() - start;
00454                                         if(length <= 0) length = track->get_length();
00455                                 }
00456                                 else
00457                                 if(mwindow->edl->local_session->get_selectionend() > 
00458                                         mwindow->edl->local_session->get_selectionstart())
00459                                 {
00460                                         start = mwindow->edl->local_session->get_selectionstart();
00461                                         length = mwindow->edl->local_session->get_selectionend() - 
00462                                                 mwindow->edl->local_session->get_selectionstart();
00463                                 }
00464 // Move to a point between two edits
00465                                 else
00466                                 if(mwindow->session->edit_highlighted)
00467                                 {
00468                                         start = mwindow->session->track_highlighted->from_units(
00469                                                 mwindow->session->edit_highlighted->startproject);
00470                                         length = mwindow->session->track_highlighted->from_units(
00471                                                 mwindow->session->edit_highlighted->length);
00472                                 }
00473 
00474                                 mwindow->insert_effects_canvas(start, length);
00475                                 redraw = 1;
00476                         }
00477                         if (mwindow->session->track_highlighted)
00478                                 result = 1;  // we have to cleanup
00479                         break;
00480 
00481                 case DRAG_ASSET:
00482                         if(mwindow->session->track_highlighted)
00483                         {
00484                                 float asset_length_float;
00485                                 int64_t asset_length_units;
00486                                 int64_t position = 0;
00487                                         
00488                                 if(mwindow->session->current_operation == DRAG_ASSET &&
00489                                         mwindow->session->drag_assets->total)
00490                                 {
00491                                         Asset *asset = mwindow->session->drag_assets->values[0];
00492 
00493                                         // we use video if we are over video and audio if we are over audio
00494                                         if (asset->video_data && mwindow->session->track_highlighted->data_type == TRACK_VIDEO)
00495                                                 asset_length_float = asset->video_length / asset->frame_rate;
00496                                         else if (asset->audio_data && mwindow->session->track_highlighted->data_type == TRACK_AUDIO)
00497                                                 asset_length_float = asset->audio_length / asset->sample_rate;
00498                                         else
00499                                         {
00500                                                 result = 1;
00501                                                 break;  // Do not do anything
00502                                         }
00503                                 }
00504                                 if(mwindow->session->current_operation == DRAG_ASSET &&
00505                                         mwindow->session->drag_clips->total)
00506                                 {
00507                                         EDL *clip = mwindow->session->drag_clips->values[0];
00508                                         asset_length_float = clip->tracks->total_length();
00509                                 }
00510                         
00511                                 asset_length_units = mwindow->session->track_highlighted->to_units(asset_length_float, 0);
00512                                 position = get_drop_position (&insertion, NULL, asset_length_units);
00513                                 if (position == -1)
00514                                 {
00515                                         result = 1;
00516                                         break;          // Do not do anything
00517                                 }
00518                                 
00519                                 double position_f = mwindow->session->track_highlighted->from_units(position);
00520                                 Track *track = mwindow->session->track_highlighted;
00521 
00522                                 if (!insertion)
00523                                 {
00524                                         // FIXME, we should create an mwindow/EDL method that overwrites, without clearing the keyframes and autos
00525                                         // Unfortunately, this is _a lot_ of work to do right
00526                                         mwindow->edl->tracks->clear(position_f, 
00527                                                 position_f + asset_length_float, 0);
00528                                 }
00529                                 mwindow->paste_assets(position_f, track);
00530                                 result = 1;    // need to be one no matter what, since we have track highlited so we have to cleanup....
00531                         }
00532                         break;
00533 
00534                 case DRAG_EDIT:
00535                         mwindow->session->current_operation = NO_OPERATION;
00536                         if(mwindow->session->track_highlighted)
00537                         {
00538                                 if(mwindow->session->track_highlighted->data_type == mwindow->session->drag_edit->track->data_type)
00539                                 {
00540                                         int64_t position = 0;
00541                                 
00542                                         position = get_drop_position (&insertion, mwindow->session->drag_edit, mwindow->session->drag_edit->length);
00543 
00544                                         if (position == -1)
00545                                         {
00546                                                 result = 1;
00547                                                 break;          // Do not do anything
00548                                         }
00549                                         
00550                                         double position_f = mwindow->session->track_highlighted->from_units(position);
00551                                         Track *track = mwindow->session->track_highlighted;
00552                                         mwindow->move_edits(mwindow->session->drag_edits,
00553                                                 track,
00554                                                 position_f,
00555                                                 !insertion);
00556                                 }
00557 
00558                                 result = 1;
00559                         }
00560                         break;
00561         }
00562 
00563 // since we don't have subwindows we have to terminate any drag operation
00564         if(result)
00565         {
00566                 if (mwindow->session->track_highlighted
00567                         || mwindow->session->edit_highlighted
00568                         || mwindow->session->plugin_highlighted
00569                         || mwindow->session->pluginset_highlighted) 
00570                         redraw = 1;
00571                 mwindow->session->track_highlighted = 0;
00572                 mwindow->session->edit_highlighted = 0;
00573                 mwindow->session->plugin_highlighted = 0;
00574                 mwindow->session->pluginset_highlighted = 0;
00575                 mwindow->session->current_operation = NO_OPERATION;
00576         }
00577 
00578 
00579 //printf("TrackCanvas::drag_stop %d %d\n", redraw, mwindow->session->current_operation);
00580         if(redraw)
00581         {
00582                 mwindow->edl->tracks->update_y_pixels(mwindow->theme);
00583                 gui->get_scrollbars();
00584                 draw();
00585                 gui->patchbay->update();
00586                 gui->cursor->update();
00587                 flash();
00588                 flush();
00589         }
00590 
00591         return result;
00592 }
00593 
00594 
00595 int64_t TrackCanvas::get_drop_position (int *is_insertion, Edit *moved_edit, int64_t moved_edit_length)
00596 {
00597         *is_insertion = 0;
00598 
00599         // get the canvas/track position
00600         int cursor_x = get_relative_cursor_x();
00601         double pos = (double)cursor_x * 
00602                 mwindow->edl->local_session->zoom_sample / 
00603                 mwindow->edl->session->sample_rate + 
00604                 (double)mwindow->edl->local_session->view_start * 
00605                 mwindow->edl->local_session->zoom_sample /
00606                 mwindow->edl->session->sample_rate;
00607         // convert to track's units to operate with them
00608         Track *track = mwindow->session->track_highlighted;
00609         // cursor relative position - depending on where we started the drag inside the edit
00610         int64_t cursor_position;
00611         if (moved_edit)  // relative cursor position depends upon grab point
00612                 cursor_position = track->to_units (pos - (mwindow->session->drag_position - moved_edit->track->from_units(moved_edit->startproject)), 1);
00613         else             // for clips and assets acts as they were grabbed in the middle
00614                 cursor_position = track->to_units (pos , 1) - moved_edit_length / 2;
00615            
00616         // we use real cursor position for affinity calculations
00617         int64_t real_cursor_position = track->to_units (pos, 0); 
00618         if (cursor_position < 0) cursor_position = 0;
00619         if (real_cursor_position < 0) real_cursor_position = 0;
00620         int64_t position = -1;
00621         int64_t span_start = 0;
00622         int64_t span_length = 0;
00623         int span_asset = 0;
00624         int last_ignore = 0; // used to make sure we can ignore the last edit if that is what we are dragging
00625 
00626         if (!track->edits->last)
00627         {
00628                 // No edits -> no problems!
00629                 position = cursor_position;
00630         }
00631         else
00632         {
00633                 Edit *fake_edit = new Edit(mwindow->edl, track);
00634                 int last2 = 0; // last2 is a hack that let us make virtual edits at the end so thing works for last edit also
00635                                // we do this by appending two VERY long virtual edits at the end
00636                 
00637                 for (Edit *edit = track->edits->first; edit || last2 < 2; )
00638                 {
00639                 
00640                         if (!edit && last_ignore)
00641                         {
00642                                 span_length += 100000000000000LL;
00643                                 last_ignore = 0;
00644                                 span_asset = 0;
00645                         } else
00646                         if (edit && 
00647                             ((moved_edit && edit == moved_edit && edit->previous && !edit->previous->asset) ||
00648                             (moved_edit && edit->previous == moved_edit  && !edit->asset)))
00649                         {
00650                                 span_length += edit->length;        // our fake edit spans over the edit we are moving
00651                                 last_ignore = 1;
00652                         } else
00653                         { // This is a virtual edit
00654                                 fake_edit->startproject = span_start;
00655                                 fake_edit->length = span_length;
00656                                 int64_t edit_x, edit_y, edit_w, edit_h;
00657                                 edit_dimensions(fake_edit, edit_x, edit_y, edit_w, edit_h);
00658                                 if (labs(edit_x - cursor_x) < HANDLE_W)                 // cursor is close to the beginning of an edit -> insertion
00659                                 {
00660                                         *is_insertion = 1;
00661                                         position = span_start;
00662                                 } else
00663                                 if (labs(edit_x + edit_w - cursor_x) < HANDLE_W)        // cursor is close to the end of an edit -> insertion
00664                                 {
00665                                         *is_insertion = 1;
00666                                         position = span_start + span_length;
00667 
00668                                 }  else
00669                                 if (!span_asset &&              // we have enough empty space to position the edit where user wants 
00670                                         span_start <= cursor_position &&
00671                                         span_start + span_length >= cursor_position + moved_edit_length)
00672                                 {
00673                                         position = cursor_position; 
00674                                 } else
00675                                 if (!span_asset &                               // we are inside an empty edit, but cannot push the edit as far as user wants, so 'resist moving it further'
00676                                         real_cursor_position >= span_start && 
00677                                         real_cursor_position < span_start + span_length && 
00678                                         span_length >= moved_edit_length)
00679                                 {
00680                                         if (llabs(real_cursor_position - span_start) < llabs(real_cursor_position - span_start - span_length))
00681                                                 position = span_start;
00682                                         else
00683                                                 position = span_start + span_length - moved_edit_length;
00684                                 } else
00685                                 if (cursor_x > edit_x && cursor_x <= edit_x + edit_w / 2) // we are inside an nonempty edit, - snap to left
00686                                 {
00687                                         *is_insertion = 1;
00688                                         position = span_start;                          
00689                                 } else
00690                                 if (cursor_x > edit_x + edit_w / 2 && cursor_x <= edit_x + edit_w) // we are inside an nonempty edit, - snap to right
00691                                 {
00692                                         *is_insertion = 1;
00693                                         position = span_start + span_length;                            
00694                                 }                               
00695                                 
00696 
00697                                 if (position != -1) 
00698                                         break;
00699                                 
00700                                 // This is the new edit
00701                                 if (edit)
00702                                 {
00703                                                 span_length = edit->length;             
00704                                                 span_start = edit->startproject;  
00705                                                 last_ignore = 0;
00706                                                 if (!edit->asset || (!moved_edit || moved_edit == edit)) 
00707                                                 {
00708                                                         if (moved_edit && moved_edit == edit)
00709                                                                 last_ignore = 1;
00710                 
00711                                                         span_asset = 0;
00712                                                 } else 
00713                                                         span_asset = 1;
00714                                 } else
00715                                 {
00716                                         span_start = span_length + span_start;
00717                                         span_length = 100000000000000LL;
00718                                         span_asset = 0;
00719                                 };
00720                                 
00721 
00722                         }
00723                         if (edit)
00724                                 edit = edit->next;
00725                         else
00726                                 last2++;
00727                         
00728                 }
00729                 delete fake_edit;
00730 
00731         }
00732         if (real_cursor_position == 0) 
00733         {
00734                 position = 0;
00735                 *is_insertion = 1;
00736         }
00737 //      printf("rcp: %lli, position: %lli, insertion: %i\n", real_cursor_position, position, *is_insertion);
00738         return position;
00739 
00740 
00741 }
00742 
00743 void TrackCanvas::draw(int force, int hide_cursor)
00744 {
00745 // Swap pixmap layers
00746 TRACE("TrackCanvas::draw 1")
00747         if(get_w() != background_pixmap->get_w() ||
00748                 get_h() != background_pixmap->get_h())
00749         {
00750                 delete background_pixmap;
00751                 background_pixmap = new BC_Pixmap(this, get_w(), get_h());
00752         }
00753 
00754 TRACE("TrackCanvas::draw 10")
00755 // Cursor disappears after resize when this is called.
00756 // Cursor doesn't redraw after editing when this isn't called.
00757         if(gui->cursor && hide_cursor) gui->cursor->hide();
00758 TRACE("TrackCanvas::draw 20")
00759         draw_top_background(get_parent(), 0, 0, get_w(), get_h(), background_pixmap);
00760 TRACE("TrackCanvas::draw 30")
00761         draw_resources(force);
00762 TRACE("TrackCanvas::draw 40")
00763         draw_overlays();
00764 UNTRACE
00765 }
00766 
00767 void TrackCanvas::update_cursor()
00768 {
00769         switch(mwindow->edl->session->editing_mode)
00770         {
00771                 case EDITING_ARROW: set_cursor(ARROW_CURSOR); break;
00772                 case EDITING_IBEAM: set_cursor(IBEAM_CURSOR); break;
00773         }
00774 }
00775 
00776 
00777 void TrackCanvas::test_timer()
00778 {
00779         if(resource_timer->get_difference() > 1000 && 
00780                 !hourglass_enabled)
00781         {
00782                 start_hourglass();
00783                 hourglass_enabled = 1;
00784         }
00785 }
00786 
00787 
00788 void TrackCanvas::draw_indexes(Asset *asset)
00789 {
00790 // Don't redraw raw samples
00791         if(asset->index_zoom > mwindow->edl->local_session->zoom_sample)
00792                 return;
00793 
00794         draw_resources(0, 1, asset);
00795 
00796         draw_overlays();
00797         draw_automation();
00798         flash();
00799         flush();
00800 }
00801 
00802 void TrackCanvas::draw_resources(int force, 
00803         int indexes_only, 
00804         Asset *index_asset)
00805 {
00806         if(!mwindow->edl->session->show_assets) return;
00807 
00808         resource_timer->update();
00809 
00810 // Age resource pixmaps for deletion
00811         if(!indexes_only)
00812                 for(int i = 0; i < resource_pixmaps.total; i++)
00813                         resource_pixmaps.values[i]->visible--;
00814 
00815         if(force)
00816                 resource_pixmaps.remove_all_objects();
00817 
00818 
00819 // Search every edit
00820         for(Track *current = mwindow->edl->tracks->first;
00821                 current;
00822                 current = NEXT)
00823         {
00824                 for(Edit *edit = current->edits->first; edit; edit = edit->next)
00825                 {
00826                         if(!edit->asset) continue;
00827                         if(indexes_only)
00828                         {
00829                                 if(edit->track->data_type != TRACK_AUDIO) continue;
00830                                 if(!edit->asset->test_path(index_asset->path)) continue;
00831                         }
00832 
00833                         int64_t edit_x, edit_y, edit_w, edit_h;
00834                         edit_dimensions(edit, edit_x, edit_y, edit_w, edit_h);
00835 
00836 // Edit is visible
00837                         if(MWindowGUI::visible(edit_x, edit_x + edit_w, 0, get_w()) &&
00838                                 MWindowGUI::visible(edit_y, edit_y + edit_h, 0, get_h()))
00839                         {
00840                                 int64_t pixmap_x, pixmap_w, pixmap_h;
00841 
00842 // Search for existing pixmap containing edit
00843                                 for(int i = 0; i < resource_pixmaps.total; i++)
00844                                 {
00845                                         ResourcePixmap* pixmap = resource_pixmaps.values[i];
00846 // Same pointer can be different edit if editing took place
00847                                         if(pixmap->edit_id == edit->id)
00848                                         {
00849                                                 pixmap->visible = 1;
00850                                                 break;
00851                                         }
00852                                 }
00853 
00854 // Get new size, offset of pixmap needed
00855                                 get_pixmap_size(edit, 
00856                                         edit_x, 
00857                                         edit_w, 
00858                                         pixmap_x, 
00859                                         pixmap_w, 
00860                                         pixmap_h);
00861 
00862 // Draw new data
00863                                 if(pixmap_w && pixmap_h)
00864                                 {
00865 // Create pixmap if it doesn't exist
00866                                         ResourcePixmap* pixmap = create_pixmap(edit, 
00867                                                 edit_x, 
00868                                                 pixmap_x, 
00869                                                 pixmap_w, 
00870                                                 pixmap_h);
00871 // Resize it if it's bigger
00872                                         if(pixmap_w > pixmap->pixmap_w ||
00873                                                 pixmap_h > pixmap->pixmap_h)
00874                                                 pixmap->resize(pixmap_w, pixmap_h);
00875                                         pixmap->draw_data(edit,
00876                                                 edit_x, 
00877                                                 edit_w, 
00878                                                 pixmap_x, 
00879                                                 pixmap_w, 
00880                                                 pixmap_h, 
00881                                                 force,
00882                                                 indexes_only);
00883 // Resize it if it's smaller
00884                                         if(pixmap_w < pixmap->pixmap_w ||
00885                                                 pixmap_h < pixmap->pixmap_h)
00886                                                 pixmap->resize(pixmap_w, pixmap_h);
00887 // Copy pixmap to background canvas
00888                                         background_pixmap->draw_pixmap(pixmap, 
00889                                                 pixmap->pixmap_x, 
00890                                                 current->y_pixel,
00891                                                 pixmap->pixmap_w,
00892                                                 edit_h);
00893                                 }
00894                         }
00895                 }
00896         }
00897 
00898 // Delete unused pixmaps
00899         if(!indexes_only)
00900                 for(int i = resource_pixmaps.total - 1; i >= 0; i--)
00901                         if(resource_pixmaps.values[i]->visible < -5)
00902                         {
00903                                 delete resource_pixmaps.values[i];
00904                                 resource_pixmaps.remove(resource_pixmaps.values[i]);
00905                         }
00906 
00907         if(hourglass_enabled) 
00908         {
00909                 stop_hourglass();
00910                 hourglass_enabled = 0;
00911         }
00912 }
00913 
00914 ResourcePixmap* TrackCanvas::create_pixmap(Edit *edit, 
00915         int64_t edit_x, 
00916         int64_t pixmap_x, 
00917         int64_t pixmap_w, 
00918         int64_t pixmap_h)
00919 {
00920         ResourcePixmap *result = 0;
00921 
00922         for(int i = 0; i < resource_pixmaps.total; i++)
00923         {
00924 //printf("TrackCanvas::create_pixmap 1 %d %d\n", edit->id, resource_pixmaps.values[i]->edit->id);
00925                 if(resource_pixmaps.values[i]->edit_id == edit->id) 
00926                 {
00927                         result = resource_pixmaps.values[i];
00928                         break;
00929                 }
00930         }
00931 
00932         if(!result)
00933         {
00934 //printf("TrackCanvas::create_pixmap 2\n");
00935                 result = new ResourcePixmap(mwindow, 
00936                         this, 
00937                         edit, 
00938                         pixmap_w, 
00939                         pixmap_h);
00940                 resource_pixmaps.append(result);
00941         }
00942 
00943 //      result->resize(pixmap_w, pixmap_h);
00944         return result;
00945 }
00946 
00947 void TrackCanvas::get_pixmap_size(Edit *edit, 
00948         int64_t edit_x, 
00949         int64_t edit_w, 
00950         int64_t &pixmap_x, 
00951         int64_t &pixmap_w,
00952         int64_t &pixmap_h)
00953 {
00954 
00955 // Align x on frame boundaries
00956 
00957 
00958 //      switch(edit->edits->track->data_type)
00959 //      {
00960 //              case TRACK_AUDIO:
00961 
00962                         pixmap_x = edit_x;
00963                         pixmap_w = edit_w;
00964                         if(pixmap_x < 0)
00965                         {
00966                                 pixmap_w -= -edit_x;
00967                                 pixmap_x = 0;
00968                         }
00969 
00970                         if(pixmap_x + pixmap_w > get_w())
00971                         {
00972                                 pixmap_w = get_w() - pixmap_x;
00973                         }
00974 
00975 //                      break;
00976 // 
00977 //              case TRACK_VIDEO:
00978 //              {
00979 //                      int64_t picon_w = (int64_t)(edit->picon_w() + 0.5);
00980 //                      int64_t frame_w = (int64_t)(edit->frame_w() + 0.5);
00981 //                      int64_t pixel_increment = MAX(picon_w, frame_w);
00982 //                      int64_t pixmap_x1 = edit_x;
00983 //                      int64_t pixmap_x2 = edit_x + edit_w;
00984 // 
00985 //                      if(pixmap_x1 < 0)
00986 //                      {
00987 //                              pixmap_x1 = (int64_t)((double)-edit_x / pixel_increment) * 
00988 //                                      pixel_increment + 
00989 //                                      edit_x;
00990 //                      }
00991 // 
00992 //                      if(pixmap_x2 > get_w())
00993 //                      {
00994 //                              pixmap_x2 = (int64_t)((double)(get_w() - edit_x) / pixel_increment + 1) * 
00995 //                                      pixel_increment + 
00996 //                                      edit_x;
00997 //                      }
00998 //                      pixmap_x = pixmap_x1;
00999 //                      pixmap_w = pixmap_x2 - pixmap_x1;
01000 //                      break;
01001 //              }
01002 //      }
01003 
01004         pixmap_h = mwindow->edl->local_session->zoom_track;
01005         if(mwindow->edl->session->show_titles) pixmap_h += mwindow->theme->title_bg_data->get_h();
01006 //printf("get_pixmap_size %d %d %d %d\n", edit_x, edit_w, pixmap_x, pixmap_w);
01007 }
01008 
01009 void TrackCanvas::edit_dimensions(Edit *edit, 
01010         int64_t &x, 
01011         int64_t &y, 
01012         int64_t &w, 
01013         int64_t &h)
01014 {
01015 //      w = Units::round(edit->track->from_units(edit->length) * 
01016 //              mwindow->edl->session->sample_rate / 
01017 //              mwindow->edl->local_session->zoom_sample);
01018 
01019         h = resource_h();
01020 
01021         x = Units::round(edit->track->from_units(edit->startproject) * 
01022                         mwindow->edl->session->sample_rate /
01023                         mwindow->edl->local_session->zoom_sample - 
01024                         mwindow->edl->local_session->view_start);
01025 
01026 // Method for calculating w so when edits are together we never get off by one error due to rounding
01027         int64_t x_next = Units::round(edit->track->from_units(edit->startproject + edit->length) * 
01028                         mwindow->edl->session->sample_rate /
01029                         mwindow->edl->local_session->zoom_sample - 
01030                         mwindow->edl->local_session->view_start);
01031         w = x_next - x;
01032 
01033         y = edit->edits->track->y_pixel;
01034 
01035         if(mwindow->edl->session->show_titles) 
01036                 h += mwindow->theme->title_bg_data->get_h();
01037 }
01038 
01039 void TrackCanvas::track_dimensions(Track *track, int64_t &x, int64_t &y, int64_t &w, int64_t &h)
01040 {
01041         x = 0;
01042         w = get_w();
01043         y = track->y_pixel;
01044         h = track->vertical_span(mwindow->theme);
01045 }
01046 
01047 
01048 void TrackCanvas::draw_paste_destination()
01049 {
01050         int current_atrack = 0;
01051         int current_vtrack = 0;
01052         int current_aedit = 0;
01053         int current_vedit = 0;
01054         int64_t w = 0;
01055         int64_t x;
01056         double position;
01057         int insertion  = 0;
01058 
01059 
01060         if((mwindow->session->current_operation == DRAG_ASSET &&
01061                         (mwindow->session->drag_assets->total ||
01062                         mwindow->session->drag_clips->total)) ||
01063                 (mwindow->session->current_operation == DRAG_EDIT &&
01064                         mwindow->session->drag_edits->total))
01065         {
01066 
01067                 Asset *asset = 0;