r665: Merged the official release 2.0.
[cinelerra_cv.git] / cinelerra / trackcanvas.C
blob5b70613deb630d897fba2b33be62d6ccf0e94dc7
1 #include "asset.h"
2 #include "autoconf.h"
3 #include "automation.h"
4 #include "bcsignals.h"
5 #include "bctimer.h"
6 #include "clip.h"
7 #include "colors.h"
8 #include "cplayback.h"
9 #include "cursors.h"
10 #include "cwindow.h"
11 #include "cwindowgui.h"
12 #include "edithandles.h"
13 #include "editpopup.h"
14 #include "edits.h"
15 #include "edl.h"
16 #include "edlsession.h"
17 #include "floatauto.h"
18 #include "floatautos.h"
19 #include "intauto.h"
20 #include "keyframe.h"
21 #include "keyframepopup.h"
22 #include "keyframes.h"
23 #include "keys.h"
24 #include "localsession.h"
25 #include "mainclock.h"
26 #include "maincursor.h"
27 #include "mainundo.h"
28 #include "maskautos.h"
29 #include "mbuttons.h"
30 #include "mtimebar.h"
31 #include "mwindow.h"
32 #include "mwindowgui.h"
33 #include "patchbay.h"
34 #include "tracking.h"
35 #include "panautos.h"
36 #include "playbackengine.h"
37 #include "playtransport.h"
38 #include "plugin.h"
39 #include "pluginpopup.h"
40 #include "pluginset.h"
41 #include "pluginserver.h"
42 #include "preferences.h"
43 #include "resourcepixmap.h"
44 #include "mainsession.h"
45 #include "transitionhandles.h"
46 #include "transitionpopup.h"
47 #include "transportque.h"
48 #include "zoombar.h"
49 #include "theme.h"
50 #include "intautos.h"
51 #include "trackcanvas.h"
52 #include "tracks.h"
53 #include "transition.h"
54 #include "vframe.h"
55 #include "apatchgui.inc"
56 #include "vpatchgui.inc"
58 #include <string.h>
60 TrackCanvas::TrackCanvas(MWindow *mwindow, MWindowGUI *gui)
61  : BC_SubWindow(mwindow->theme->mcanvas_x,
62         mwindow->theme->mcanvas_y,
63         gui->view_w,
64         gui->view_h)
66         this->mwindow = mwindow;
67         this->gui = gui;
68         current_end = 0;
69         selection_midpoint1 = selection_midpoint2 = 0;
70         selection_type = 0;
71         region_selected = 0;
72         handle_selected = 0;
73         auto_selected = 0;
74         translate_selected = 0;
75         which_handle = 0;
76         handle_pixel = 0;
77         drag_scroll = 0;
78         drag_popup = 0;
79         active = 0;
80         temp_picon = 0;
81         resource_timer = new Timer;
82         hourglass_enabled = 0;
85 TrackCanvas::~TrackCanvas()
87         for(int i = 0; i < resource_pixmaps.total; i++)
88                 delete resource_pixmaps.values[i];
89 //      delete transition_handles;
90         delete edit_handles;
91         delete keyframe_pixmap;
92         delete camerakeyframe_pixmap;
93         delete modekeyframe_pixmap;
94         delete pankeyframe_pixmap;
95         delete projectorkeyframe_pixmap;
96         delete maskkeyframe_pixmap;
97         delete background_pixmap;
98         if(temp_picon) delete temp_picon;
99         delete resource_timer;
102 int TrackCanvas::create_objects()
104         background_pixmap = new BC_Pixmap(this, get_w(), get_h());
105 //      transition_handles = new TransitionHandles(mwindow, this);
106         edit_handles = new EditHandles(mwindow, this);
107         keyframe_pixmap = new BC_Pixmap(this, mwindow->theme->keyframe_data, PIXMAP_ALPHA);
108         camerakeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->camerakeyframe_data, PIXMAP_ALPHA);
109         modekeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->modekeyframe_data, PIXMAP_ALPHA);
110         pankeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->pankeyframe_data, PIXMAP_ALPHA);
111         projectorkeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->projectorkeyframe_data, PIXMAP_ALPHA);
112         maskkeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->maskkeyframe_data, PIXMAP_ALPHA);
113         draw();
114         update_cursor();
115         flash();
116         return 0;
119 void TrackCanvas::resize_event()
121 //printf("TrackCanvas::resize_event 1\n");
122         draw(0, 0);
123         flash();
124 //printf("TrackCanvas::resize_event 2\n");
127 int TrackCanvas::keypress_event()
129         int result = 0;
132         return result;
135 int TrackCanvas::drag_motion()
137         int cursor_x = get_relative_cursor_x();
138         int cursor_y = get_relative_cursor_y();
139         Track *over_track = 0;
140         Edit *over_edit = 0;
141         PluginSet *over_pluginset = 0;
142         Plugin *over_plugin = 0;
143         int redraw = 0;
146         if(drag_popup)
147         {
148                 drag_popup->cursor_motion_event();
149         }
152 // there's no point in drawing highlights has until drag operation has been set
153         if (!mwindow->session->current_operation)
154                 return 0;
156         if(get_cursor_over_window() &&
157                 cursor_x >= 0 && 
158                 cursor_y >= 0 && 
159                 cursor_x < get_w() && 
160                 cursor_y < get_h())
161         {
162 //printf("drag motion 1 %d\n", ctrl_down());
163                 if(mwindow->session->free_drag) redraw = 1;
164                 if(ctrl_down()) 
165                 {
166                         redraw = 1;
167                         mwindow->session->free_drag = 1;
168                 }
169                 else
170                 {
171                         mwindow->session->free_drag = 0;
172                 }
174 // Find the edit and track the cursor is over
175                 for(Track *track = mwindow->edl->tracks->first; track; track = track->next)
176                 {
177                         int64_t track_x, track_y, track_w, track_h;
178                         track_dimensions(track, track_x, track_y, track_w, track_h);
180                         if(cursor_y >= track_y && 
181                                 cursor_y < track_y + track_h)
182                         {
183                                 over_track = track;
184                                 for(Edit *edit = track->edits->first; edit; edit = edit->next)
185                                 {
186                                         int64_t edit_x, edit_y, edit_w, edit_h;
187                                         edit_dimensions(edit, edit_x, edit_y, edit_w, edit_h);
189                                         if(cursor_x >= edit_x && 
190                                                 cursor_y >= edit_y && 
191                                                 cursor_x < edit_x + edit_w && 
192                                                 cursor_y < edit_y + edit_h)
193                                         {
194                                                 over_edit = edit;
195                                                 break;
196                                         }
197                                 }
199                                 for(int i = 0; i < track->plugin_set.total; i++)
200                                 {
201                                         PluginSet *pluginset = track->plugin_set.values[i];
202                                         
205                                         for(Plugin *plugin = (Plugin*)pluginset->first;
206                                                 plugin;
207                                                 plugin = (Plugin*)plugin->next)
208                                         {
209                                                 int64_t plugin_x, plugin_y, plugin_w, plugin_h;
210                                                 plugin_dimensions(plugin, plugin_x, plugin_y, plugin_w, plugin_h);
211                                                 
212                                                 if(cursor_y >= plugin_y &&
213                                                         cursor_y < plugin_y + plugin_h)
214                                                 {
215                                                         over_pluginset = plugin->plugin_set;
216                                                 
217                                                         if(cursor_x >= plugin_x &&
218                                                                 cursor_x < plugin_x + plugin_w)
219                                                         {
220                                                                 over_plugin = plugin;
221                                                                 break;
222                                                         }
223                                                 }
224                                         }
225                                 }
226                                 break;
227                         }
228                 }
229         }
231         if (!over_track)        // check for pastes from patchbay
232                 over_track = mwindow->gui->patchbay->is_over_track();
234         if(mwindow->session->track_highlighted != over_track) 
235         {
236                 mwindow->session->track_highlighted = over_track;
237                 redraw = 1;
238         }
240         if(mwindow->session->edit_highlighted != over_edit)
241         {
242                 mwindow->session->edit_highlighted = over_edit;
243                 redraw = 1;
244         }
246         if(mwindow->session->pluginset_highlighted != over_pluginset)
247         {
248                 mwindow->session->pluginset_highlighted = over_pluginset;
249                 redraw = 1;
250         }
252         if(mwindow->session->plugin_highlighted != over_plugin)
253         {
254                 mwindow->session->plugin_highlighted = over_plugin;
255                 redraw = 1;
256         }
258         if (mwindow->session->current_operation == DRAG_ASSET ||
259           mwindow->session->current_operation == DRAG_EDIT)
261         {
262                 redraw = 1;
263         }
265 //printf("TrackCanvas::drag_motion 2 %p\n", mwindow->session->track_highlighted);
266         if(redraw)
267         {
268                 lock_window("TrackCanvas::drag_motion");
269                 draw_overlays();
270                 flash();
271                 unlock_window();
272         }
274         return 0;
277 int TrackCanvas::drag_start_event()
279         int result = 0;
280         int redraw = 0;
281         int rerender = 0;
282         int new_cursor, update_cursor;
284         if(mwindow->session->current_operation != NO_OPERATION) return 0;
286         if(is_event_win())
287         {
288                 if(do_plugins(get_drag_x(), 
289                         get_drag_y(), 
290                         1,
291                         0,
292                         redraw,
293                         rerender))
294                 {
295                         result = 1;
296                 }
297                 else
298                 if(do_edits(get_drag_x(),
299                         get_drag_y(),
300                         0,
301                         1,
302                         redraw,
303                         rerender,
304                         new_cursor,
305                         update_cursor))
306                 {
307                         result = 1;
308                 }
309         }
311         if(result) mwindow->session->free_drag = ctrl_down();
313         return result;
316 int TrackCanvas::drag_motion_event()
318         return drag_motion();
321 int TrackCanvas::cursor_leave_event()
323 // Because drag motion calls get_cursor_over_window we can be sure that
324 // all highlights get deleted now.
325 // This ended up blocking keyboard input from the drag operations.
326         return 0;
327 //      return drag_motion();
331 int TrackCanvas::drag_stop_event()
333         int result = drag_stop();
335         if(drag_popup)
336         {
337                 delete drag_popup;
338                 drag_popup = 0;
339         }
340         return result;
344 int TrackCanvas::drag_stop()
346 // In most cases the editing routine redraws and not the drag_stop
347         int result = 0, redraw = 0;
349         int insertion = 0;           // used in drag and drop mode
350         switch(mwindow->session->current_operation)
351         {
352                 case DRAG_VTRANSITION:
353                 case DRAG_ATRANSITION:
354                         if(mwindow->session->edit_highlighted)
355                         {
356                                 if((mwindow->session->current_operation == DRAG_ATRANSITION &&
357                                         mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
358                                         (mwindow->session->current_operation == DRAG_VTRANSITION &&
359                                         mwindow->session->track_highlighted->data_type == TRACK_VIDEO))
360                                 {
361                                         mwindow->session->current_operation = NO_OPERATION;
362                                         mwindow->paste_transition();
363                                         result = 1;
364                                 }
365                         }
366                         redraw = 1;
367                         break;
372 // Behavior for dragged plugins is limited by the fact that a shared plugin
373 // can only refer to a standalone plugin that exists in the same position in
374 // time.  Dragging a plugin from one point in time to another can't produce
375 // a shared plugin to the original plugin.  In this case we relocate the
376 // plugin instead of sharing it.
377                 case DRAG_AEFFECT_COPY:
378                 case DRAG_VEFFECT_COPY:
379                         if(mwindow->session->track_highlighted &&
380                                 ((mwindow->session->current_operation == DRAG_AEFFECT_COPY &&
381                                         mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
382                                         (mwindow->session->current_operation == DRAG_VEFFECT_COPY &&
383                                         mwindow->session->track_highlighted->data_type == TRACK_VIDEO)))
384                         {
385                                 mwindow->session->current_operation = NO_OPERATION;
387 // Insert shared plugin in source
388                                 if(mwindow->session->track_highlighted != mwindow->session->drag_plugin->track &&
389                                         !mwindow->session->plugin_highlighted &&
390                                         !mwindow->session->pluginset_highlighted)
391                                 {
392 // Move plugin if different startproject
393                                         mwindow->move_effect(mwindow->session->drag_plugin,
394                                                 0,
395                                                 mwindow->session->track_highlighted,
396                                                 0);
397                                         result = 1;
398                                 }
399                                 else
400 // Move source to different location
401                                 if(mwindow->session->pluginset_highlighted)
402                                 {
403 //printf("TrackCanvas::drag_stop 6\n");
404                                         if(mwindow->session->plugin_highlighted)
405                                         {
406                                                 mwindow->move_effect(mwindow->session->drag_plugin,
407                                                         mwindow->session->plugin_highlighted->plugin_set,
408                                                         0,
409                                                         mwindow->session->plugin_highlighted->startproject);
410                                         }
411                                         else
412                                         {
413                                                 mwindow->move_effect(mwindow->session->drag_plugin,
414                                                         mwindow->session->pluginset_highlighted,
415                                                         0,
416                                                         mwindow->session->pluginset_highlighted->length());
417                                         }
418                                         result = 1;
419                                 }
420                                 else
421 // Move to a new plugin set between two edits
422                                 if(mwindow->session->edit_highlighted)
423                                 {
424                                         mwindow->move_effect(mwindow->session->drag_plugin,
425                                                 0,
426                                                 mwindow->session->track_highlighted,
427                                                 mwindow->session->edit_highlighted->startproject);
428                                         result = 1;
429                                 }
430                                 else
431 // Move to a new plugin set
432                                 if(mwindow->session->track_highlighted)
433                                 {
434                                         mwindow->move_effect(mwindow->session->drag_plugin,
435                                                 0,
436                                                 mwindow->session->track_highlighted,
437                                                 0);
438                                         result = 1;
439                                 }
440                         }
441                         break;
443                 case DRAG_AEFFECT:
444                 case DRAG_VEFFECT:
445                         if(mwindow->session->track_highlighted && 
446                                 ((mwindow->session->current_operation == DRAG_AEFFECT &&
447                                 mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
448                                 (mwindow->session->current_operation == DRAG_VEFFECT &&
449                                 mwindow->session->track_highlighted->data_type == TRACK_VIDEO)))
450                         {
451 // Drop all the effects
452                                 PluginSet *plugin_set = mwindow->session->pluginset_highlighted;
453                                 Track *track = mwindow->session->track_highlighted;
454                                 double start = 0;
455                                 double length = track->get_length();
457                                 if(mwindow->session->plugin_highlighted)
458                                 {
459                                         start = track->from_units(mwindow->session->plugin_highlighted->startproject);
460                                         length = track->from_units(mwindow->session->plugin_highlighted->length);
461                                         if(length <= 0) length = track->get_length();
462                                 }
463                                 else
464                                 if(mwindow->session->pluginset_highlighted)
465                                 {
466                                         start = track->from_units(plugin_set->length());
467                                         length = track->get_length() - start;
468                                         if(length <= 0) length = track->get_length();
469                                 }
470                                 else
471                                 if(mwindow->edl->local_session->get_selectionend() > 
472                                         mwindow->edl->local_session->get_selectionstart())
473                                 {
474                                         start = mwindow->edl->local_session->get_selectionstart();
475                                         length = mwindow->edl->local_session->get_selectionend() - 
476                                                 mwindow->edl->local_session->get_selectionstart();
477                                 }
478 // Move to a point between two edits
479                                 else
480                                 if(mwindow->session->edit_highlighted)
481                                 {
482                                         start = mwindow->session->track_highlighted->from_units(
483                                                 mwindow->session->edit_highlighted->startproject);
484                                         length = mwindow->session->track_highlighted->from_units(
485                                                 mwindow->session->edit_highlighted->length);
486                                 }
488                                 mwindow->insert_effects_canvas(start, length);
489                                 redraw = 1;
490                         }
491                         if (mwindow->session->track_highlighted)
492                                 result = 1;  // we have to cleanup
493                         break;
495                 case DRAG_ASSET:
496                         if(mwindow->session->track_highlighted)
497                         {
498                                 float asset_length_float;
499                                 int64_t asset_length_units;
500                                 int64_t position = 0;
501                                         
502                                 if(mwindow->session->current_operation == DRAG_ASSET &&
503                                         mwindow->session->drag_assets->total)
504                                 {
505                                         Asset *asset = mwindow->session->drag_assets->values[0];
507                                         // we use video if we are over video and audio if we are over audio
508                                         if (asset->video_data && mwindow->session->track_highlighted->data_type == TRACK_VIDEO)
509                                                 asset_length_float = asset->video_length / asset->frame_rate;
510                                         else
511                                                 asset_length_float = asset->audio_length / asset->sample_rate;
512                                 }
513                                 if(mwindow->session->current_operation == DRAG_ASSET &&
514                                         mwindow->session->drag_clips->total)
515                                 {
516                                         EDL *clip = mwindow->session->drag_clips->values[0];
517                                         asset_length_float = clip->tracks->total_length();
518                                 }
519                         
520                                 asset_length_units = mwindow->session->track_highlighted->to_units(asset_length_float, 0);
521                                 position = get_drop_position (&insertion, NULL, asset_length_units);
522                                 if (position == -1)
523                                 {
524                                         result = 1;
525                                         break;          // Do not do anything
526                                 }
527                                 
528                                 double position_f = mwindow->session->track_highlighted->from_units(position);
529                                 Track *track = mwindow->session->track_highlighted;
531                                 if (!insertion)
532                                 {
533                                         // FIXME, we should create an mwindow/EDL method that overwrites, without clearing the keyframes and autos
534                                         // Unfortunately, this is _a lot_ of work to do right
535                                         mwindow->edl->tracks->clear(position_f, 
536                                                 position_f + asset_length_float, 0);
537                                 }
538                                 mwindow->paste_assets(position_f, track);
539                                 result = 1;    // need to be one no matter what, since we have track highlited so we have to cleanup....
540                         }
541                         break;
543                 case DRAG_EDIT:
544                         mwindow->session->current_operation = NO_OPERATION;
545                         if(mwindow->session->track_highlighted)
546                         {
547                                 if(mwindow->session->track_highlighted->data_type == mwindow->session->drag_edit->track->data_type)
548                                 {
549                                         int64_t position = 0;
550                                 
551                                         position = get_drop_position (&insertion, mwindow->session->drag_edit, mwindow->session->drag_edit->length);
553                                         if (position == -1)
554                                         {
555                                                 result = 1;
556                                                 break;          // Do not do anything
557                                         }
558                                         
559                                         double position_f;
560                                         if(mwindow->session->free_drag)
561                                                 position_f = (double)(get_cursor_x() + mwindow->edl->local_session->view_start) *
562                                                         mwindow->edl->local_session->zoom_sample /
563                                                         mwindow->edl->session->sample_rate;
564                                         else
565                                         {
566                                                 position = mwindow->session->edit_highlighted ?
567                                                         mwindow->session->edit_highlighted->startproject :
568                                                         mwindow->session->track_highlighted->edits->length();
569                                                 position_f = mwindow->session->track_highlighted->from_units(position);
570                                         }
571                                         Track *track = mwindow->session->track_highlighted;
572                                         mwindow->move_edits(mwindow->session->drag_edits,
573                                                 track,
574                                                 position_f,
575                                                 !insertion);
576                                 }
578                                 result = 1;
579                         }
580                         break;
581         }
583 // since we don't have subwindows we have to terminate any drag operation
584         if(result)
585         {
586                 if (mwindow->session->track_highlighted
587                         || mwindow->session->edit_highlighted
588                         || mwindow->session->plugin_highlighted
589                         || mwindow->session->pluginset_highlighted) 
590                         redraw = 1;
591                 mwindow->session->track_highlighted = 0;
592                 mwindow->session->edit_highlighted = 0;
593                 mwindow->session->plugin_highlighted = 0;
594                 mwindow->session->pluginset_highlighted = 0;
595                 mwindow->session->current_operation = NO_OPERATION;
596         }
599 //printf("TrackCanvas::drag_stop %d %d\n", redraw, mwindow->session->current_operation);
600         if(redraw)
601         {
602                 mwindow->edl->tracks->update_y_pixels(mwindow->theme);
603                 gui->get_scrollbars();
604                 draw();
605                 gui->patchbay->update();
606                 gui->cursor->update();
607                 flash();
608                 flush();
609         }
611         return result;
615 int64_t TrackCanvas::get_drop_position (int *is_insertion, Edit *moved_edit, int64_t moved_edit_length)
617         *is_insertion = 0;
619         // get the canvas/track position
620         int cursor_x = get_relative_cursor_x();
621         double pos = (double)cursor_x * 
622                 mwindow->edl->local_session->zoom_sample / 
623                 mwindow->edl->session->sample_rate + 
624                 (double)mwindow->edl->local_session->view_start * 
625                 mwindow->edl->local_session->zoom_sample /
626                 mwindow->edl->session->sample_rate;
627         // convert to track's units to operate with them
628         Track *track = mwindow->session->track_highlighted;
629         // cursor relative position - depending on where we started the drag inside the edit
630         int64_t cursor_position;
631         if (moved_edit)  // relative cursor position depends upon grab point
632                 cursor_position = track->to_units (pos - (mwindow->session->drag_position - moved_edit->track->from_units(moved_edit->startproject)), 1);
633         else             // for clips and assets acts as they were grabbed in the middle
634                 cursor_position = track->to_units (pos , 1) - moved_edit_length / 2;
635            
636         // we use real cursor position for affinity calculations
637         int64_t real_cursor_position = track->to_units (pos, 0); 
638         if (cursor_position < 0) cursor_position = 0;
639         if (real_cursor_position < 0) real_cursor_position = 0;
640         int64_t position = -1;
641         int64_t span_start = 0;
642         int64_t span_length = 0;
643         int span_asset = 0;
644         int last_ignore = 0; // used to make sure we can ignore the last edit if that is what we are dragging
646         if (!track->edits->last)
647         {
648                 // No edits -> no problems!
649                 position = cursor_position;
650         }
651         else
652         {
653                 Edit *fake_edit = new Edit(mwindow->edl, track);
654                 int last2 = 0; // last2 is a hack that let us make virtual edits at the end so thing works for last edit also
655                                // we do this by appending two VERY long virtual edits at the end
656                 
657                 for (Edit *edit = track->edits->first; edit || last2 < 2; )
658                 {
659                 
660                         if (!edit && last_ignore)
661                         {
662                                 span_length += 100000000000000LL;
663                                 last_ignore = 0;
664                                 span_asset = 0;
665                         } else
666                         if (edit && 
667                             ((moved_edit && edit == moved_edit && edit->previous && !edit->previous->asset) ||
668                             (moved_edit && edit->previous == moved_edit  && !edit->asset)))
669                         {
670                                 span_length += edit->length;        // our fake edit spans over the edit we are moving
671                                 last_ignore = 1;
672                         } else
673                         { // This is a virtual edit
674                                 fake_edit->startproject = span_start;
675                                 fake_edit->length = span_length;
676                                 int64_t edit_x, edit_y, edit_w, edit_h;
677                                 edit_dimensions(fake_edit, edit_x, edit_y, edit_w, edit_h);
678                                 if (labs(edit_x - cursor_x) < HANDLE_W)                 // cursor is close to the beginning of an edit -> insertion
679                                 {
680                                         *is_insertion = 1;
681                                         position = span_start;
682                                 } else
683                                 if (labs(edit_x + edit_w - cursor_x) < HANDLE_W)        // cursor is close to the end of an edit -> insertion
684                                 {
685                                         *is_insertion = 1;
686                                         position = span_start + span_length;
688                                 }  else
689                                 if (!span_asset &&              // we have enough empty space to position the edit where user wants 
690                                         span_start <= cursor_position &&
691                                         span_start + span_length >= cursor_position + moved_edit_length)
692                                 {
693                                         position = cursor_position; 
694                                 } else
695                                 if (!span_asset &                               // we are inside an empty edit, but cannot push the edit as far as user wants, so 'resist moving it further'
696                                         real_cursor_position >= span_start && 
697                                         real_cursor_position < span_start + span_length && 
698                                         span_length >= moved_edit_length)
699                                 {
700                                         if (llabs(real_cursor_position - span_start) < llabs(real_cursor_position - span_start - span_length))
701                                                 position = span_start;
702                                         else
703                                                 position = span_start + span_length - moved_edit_length;
704                                 } else
705                                 if (cursor_x > edit_x && cursor_x <= edit_x + edit_w / 2) // we are inside an nonempty edit, - snap to left
706                                 {
707                                         *is_insertion = 1;
708                                         position = span_start;                          
709                                 } else
710                                 if (cursor_x > edit_x + edit_w / 2 && cursor_x <= edit_x + edit_w) // we are inside an nonempty edit, - snap to right
711                                 {
712                                         *is_insertion = 1;
713                                         position = span_start + span_length;                            
714                                 }                               
715                                 
717                                 if (position != -1) 
718                                         break;
719                                 
720                                 // This is the new edit
721                                 if (edit)
722                                 {
723                                                 span_length = edit->length;             
724                                                 span_start = edit->startproject;  
725                                                 last_ignore = 0;
726                                                 if (!edit->asset || (!moved_edit || moved_edit == edit)) 
727                                                 {
728                                                         if (moved_edit && moved_edit == edit)
729                                                                 last_ignore = 1;
730                 
731                                                         span_asset = 0;
732                                                 } else 
733                                                         span_asset = 1;
734                                 } else
735                                 {
736                                         span_start = span_length + span_start;
737                                         span_length = 100000000000000LL;
738                                         span_asset = 0;
739                                 };
740                                 
742                         }
743                         if (edit)
744                                 edit = edit->next;
745                         else
746                                 last2++;
747                         
748                 }
749                 delete fake_edit;
751         }
752         if (real_cursor_position == 0) 
753         {
754                 position = 0;
755                 *is_insertion = 1;
756         }
757 //      printf("rcp: %lli, position: %lli, insertion: %i\n", real_cursor_position, position, *is_insertion);
758         return position;
763 void TrackCanvas::draw(int force, int hide_cursor)
765 // Swap pixmap layers
766 TRACE("TrackCanvas::draw 1")
767         if(get_w() != background_pixmap->get_w() ||
768                 get_h() != background_pixmap->get_h())
769         {
770                 delete background_pixmap;
771                 background_pixmap = new BC_Pixmap(this, get_w(), get_h());
772         }
774 TRACE("TrackCanvas::draw 10")
775 // Cursor disappears after resize when this is called.
776 // Cursor doesn't redraw after editing when this isn't called.
777         if(gui->cursor && hide_cursor) gui->cursor->hide();
778 TRACE("TrackCanvas::draw 20")
779         draw_top_background(get_parent(), 0, 0, get_w(), get_h(), background_pixmap);
780 TRACE("TrackCanvas::draw 30")
781         draw_resources(force);
782 TRACE("TrackCanvas::draw 40")
783         draw_overlays();
784 UNTRACE
787 void TrackCanvas::update_cursor()
789         switch(mwindow->edl->session->editing_mode)
790         {
791                 case EDITING_ARROW: set_cursor(ARROW_CURSOR); break;
792                 case EDITING_IBEAM: set_cursor(IBEAM_CURSOR); break;
793         }
797 void TrackCanvas::test_timer()
799         if(resource_timer->get_difference() > 1000 && 
800                 !hourglass_enabled)
801         {
802                 start_hourglass();
803                 hourglass_enabled = 1;
804         }
808 void TrackCanvas::draw_indexes(Asset *asset)
810 // Don't redraw raw samples
811         if(asset->index_zoom > mwindow->edl->local_session->zoom_sample)
812                 return;
814         draw_resources(0, 1, asset);
816         draw_overlays();
817         draw_automation();
818         flash();
819         flush();
822 void TrackCanvas::draw_resources(int force, 
823         int indexes_only, 
824         Asset *index_asset)
826         if(!mwindow->edl->session->show_assets) return;
828         resource_timer->update();
830 // Age resource pixmaps for deletion
831         if(!indexes_only)
832                 for(int i = 0; i < resource_pixmaps.total; i++)
833                         resource_pixmaps.values[i]->visible--;
835         if(force)
836                 resource_pixmaps.remove_all_objects();
839 // Search every edit
840         for(Track *current = mwindow->edl->tracks->first;
841                 current;
842                 current = NEXT)
843         {
844                 for(Edit *edit = current->edits->first; edit; edit = edit->next)
845                 {
846                         if(!edit->asset) continue;
847                         if(indexes_only)
848                         {
849                                 if(edit->track->data_type != TRACK_AUDIO) continue;
850                                 if(!edit->asset->test_path(index_asset->path)) continue;
851                         }
853                         int64_t edit_x, edit_y, edit_w, edit_h;
854                         edit_dimensions(edit, edit_x, edit_y, edit_w, edit_h);
856 // Edit is visible
857                         if(MWindowGUI::visible(edit_x, edit_x + edit_w, 0, get_w()) &&
858                                 MWindowGUI::visible(edit_y, edit_y + edit_h, 0, get_h()))
859                         {
860                                 int64_t pixmap_x, pixmap_w, pixmap_h;
862 // Search for existing pixmap containing edit
863                                 for(int i = 0; i < resource_pixmaps.total; i++)
864                                 {
865                                         ResourcePixmap* pixmap = resource_pixmaps.values[i];
866 // Same pointer can be different edit if editing took place
867                                         if(pixmap->edit_id == edit->id)
868                                         {
869                                                 pixmap->visible = 1;
870                                                 break;
871                                         }
872                                 }
874 // Get new size, offset of pixmap needed
875                                 get_pixmap_size(edit, 
876                                         edit_x, 
877                                         edit_w, 
878                                         pixmap_x, 
879                                         pixmap_w, 
880                                         pixmap_h);
882 // Draw new data
883                                 if(pixmap_w && pixmap_h)
884                                 {
885 // Create pixmap if it doesn't exist
886                                         ResourcePixmap* pixmap = create_pixmap(edit, 
887                                                 edit_x, 
888                                                 pixmap_x, 
889                                                 pixmap_w, 
890                                                 pixmap_h);
891 // Resize it if it's bigger
892                                         if(pixmap_w > pixmap->pixmap_w ||
893                                                 pixmap_h > pixmap->pixmap_h)
894                                                 pixmap->resize(pixmap_w, pixmap_h);
895                                         pixmap->draw_data(edit,
896                                                 edit_x, 
897                                                 edit_w, 
898                                                 pixmap_x, 
899                                                 pixmap_w, 
900                                                 pixmap_h, 
901                                                 force,
902                                                 indexes_only);
903 // Resize it if it's smaller
904                                         if(pixmap_w < pixmap->pixmap_w ||
905                                                 pixmap_h < pixmap->pixmap_h)
906                                                 pixmap->resize(pixmap_w, pixmap_h);
907 // Copy pixmap to background canvas
908                                         background_pixmap->draw_pixmap(pixmap, 
909                                                 pixmap->pixmap_x, 
910                                                 current->y_pixel,
911                                                 pixmap->pixmap_w,
912                                                 edit_h);
913                                 }
914                         }
915                 }
916         }
918 // Delete unused pixmaps
919         if(!indexes_only)
920                 for(int i = resource_pixmaps.total - 1; i >= 0; i--)
921                         if(resource_pixmaps.values[i]->visible < -5)
922                         {
923                                 delete resource_pixmaps.values[i];
924                                 resource_pixmaps.remove(resource_pixmaps.values[i]);
925                         }
927         if(hourglass_enabled) 
928         {
929                 stop_hourglass();
930                 hourglass_enabled = 0;
931         }
934 ResourcePixmap* TrackCanvas::create_pixmap(Edit *edit, 
935         int64_t edit_x, 
936         int64_t pixmap_x, 
937         int64_t pixmap_w, 
938         int64_t pixmap_h)
940         ResourcePixmap *result = 0;
942         for(int i = 0; i < resource_pixmaps.total; i++)
943         {
944 //printf("TrackCanvas::create_pixmap 1 %d %d\n", edit->id, resource_pixmaps.values[i]->edit->id);
945                 if(resource_pixmaps.values[i]->edit_id == edit->id) 
946                 {
947                         result = resource_pixmaps.values[i];
948                         break;
949                 }
950         }
952         if(!result)
953         {
954 //printf("TrackCanvas::create_pixmap 2\n");
955                 result = new ResourcePixmap(mwindow, 
956                         this, 
957                         edit, 
958                         pixmap_w, 
959                         pixmap_h);
960                 resource_pixmaps.append(result);
961         }
963 //      result->resize(pixmap_w, pixmap_h);
964         return result;
967 void TrackCanvas::get_pixmap_size(Edit *edit, 
968         int64_t edit_x, 
969         int64_t edit_w, 
970         int64_t &pixmap_x, 
971         int64_t &pixmap_w,
972         int64_t &pixmap_h)
975 // Align x on frame boundaries
978 //      switch(edit->edits->track->data_type)
979 //      {
980 //              case TRACK_AUDIO:
982                         pixmap_x = edit_x;
983                         pixmap_w = edit_w;
984                         if(pixmap_x < 0)
985                         {
986                                 pixmap_w -= -edit_x;
987                                 pixmap_x = 0;
988                         }
990                         if(pixmap_x + pixmap_w > get_w())
991                         {
992                                 pixmap_w = get_w() - pixmap_x;
993                         }
995 //                      break;
996 // 
997 //              case TRACK_VIDEO:
998 //              {
999 //                      int64_t picon_w = (int64_t)(edit->picon_w() + 0.5);
1000 //                      int64_t frame_w = (int64_t)(edit->frame_w() + 0.5);
1001 //                      int64_t pixel_increment = MAX(picon_w, frame_w);
1002 //                      int64_t pixmap_x1 = edit_x;
1003 //                      int64_t pixmap_x2 = edit_x + edit_w;
1004 // 
1005 //                      if(pixmap_x1 < 0)
1006 //                      {
1007 //                              pixmap_x1 = (int64_t)((double)-edit_x / pixel_increment) * 
1008 //                                      pixel_increment + 
1009 //                                      edit_x;
1010 //                      }
1011 // 
1012 //                      if(pixmap_x2 > get_w())
1013 //                      {
1014 //                              pixmap_x2 = (int64_t)((double)(get_w() - edit_x) / pixel_increment + 1) * 
1015 //                                      pixel_increment + 
1016 //                                      edit_x;
1017 //                      }
1018 //                      pixmap_x = pixmap_x1;
1019 //                      pixmap_w = pixmap_x2 - pixmap_x1;
1020 //                      break;
1021 //              }
1022 //      }
1024         pixmap_h = mwindow->edl->local_session->zoom_track;
1025         if(mwindow->edl->session->show_titles) pixmap_h += mwindow->theme->title_bg_data->get_h();
1026 //printf("get_pixmap_size %d %d %d %d\n", edit_x, edit_w, pixmap_x, pixmap_w);
1029 void TrackCanvas::edit_dimensions(Edit *edit, 
1030         int64_t &x, 
1031         int64_t &y, 
1032         int64_t &w, 
1033         int64_t &h)
1035 //      w = Units::round(edit->track->from_units(edit->length) * 
1036 //              mwindow->edl->session->sample_rate / 
1037 //              mwindow->edl->local_session->zoom_sample);
1039         h = resource_h();
1041         x = Units::round(edit->track->from_units(edit->startproject) * 
1042                         mwindow->edl->session->sample_rate /
1043                         mwindow->edl->local_session->zoom_sample - 
1044                         mwindow->edl->local_session->view_start);
1046 // Method for calculating w so when edits are together we never get off by one error due to rounding
1047         int64_t x_next = Units::round(edit->track->from_units(edit->startproject + edit->length) * 
1048                         mwindow->edl->session->sample_rate /
1049                         mwindow->edl->local_session->zoom_sample - 
1050                         mwindow->edl->local_session->view_start);
1051         w = x_next - x;
1053         y = edit->edits->track->y_pixel;
1055         if(mwindow->edl->session->show_titles) 
1056                 h += mwindow->theme->title_bg_data->get_h();
1059 void TrackCanvas::track_dimensions(Track *track, int64_t &x, int64_t &y, int64_t &w, int64_t &h)
1061         x = 0;
1062         w = get_w();
1063         y = track->y_pixel;
1064         h = track->vertical_span(mwindow->theme);
1068 void TrackCanvas::draw_paste_destination()
1070         int current_atrack = 0;
1071         int current_vtrack = 0;
1072         int current_aedit = 0;
1073         int current_vedit = 0;
1074         int64_t w = 0;
1075         int64_t x;
1076         double position;
1077         int insertion  = 0;
1080         if((mwindow->session->current_operation == DRAG_ASSET &&
1081                         (mwindow->session->drag_assets->total ||
1082                         mwindow->session->drag_clips->total)) ||
1083                 (mwindow->session->current_operation == DRAG_EDIT &&
1084                         mwindow->session->drag_edits->total))
1085         {
1087                 Asset *asset = 0;
1088                 EDL *clip = 0;
1089                 int draw_box = 0;
1091                 if(mwindow->session->current_operation == DRAG_ASSET &&
1092                         mwindow->session->drag_assets->total)
1093                         asset = mwindow->session->drag_assets->values[0];
1095                 if(mwindow->session->current_operation == DRAG_ASSET &&
1096                         mwindow->session->drag_clips->total)
1097                         clip = mwindow->session->drag_clips->values[0];
1099 // Get destination track
1100                 for(Track *dest = mwindow->session->track_highlighted; 
1101                         dest; 
1102                         dest = dest->next)
1103                 {
1104                         if(dest->record)
1105                         {
1106 // Get source width in pixels
1107                                 w = -1;
1109 // Use current cursor position
1110                                 if(mwindow->session->free_drag)
1111                                         position = (double)(get_cursor_x() + mwindow->edl->local_session->view_start) *
1112                                                 mwindow->edl->local_session->zoom_sample /
1113                                                 mwindow->edl->session->sample_rate;
1114                                 else
1115 // Use start of highlighted edit
1116                                 if(mwindow->session->edit_highlighted)
1117                                         position = mwindow->session->track_highlighted->from_units(
1118                                                 mwindow->session->edit_highlighted->startproject);
1119                                 else
1120 // Use end of highlighted track, disregarding effects
1121                                         position = mwindow->session->track_highlighted->from_units(
1122                                                 mwindow->session->track_highlighted->edits->length());
1125                                 if(dest->data_type == TRACK_AUDIO)
1126                                 {
1127                                         if(asset && current_atrack < asset->channels)
1128                                         {
1129                                         
1130                                                 w = Units::to_int64((double)asset->audio_length /
1131                                                         asset->sample_rate *
1132                                                         mwindow->edl->session->sample_rate / 
1133                                                         mwindow->edl->local_session->zoom_sample);
1134                                                 
1135                                         // FIXME: more obvious, get_drop_position should be called only ONCE - for highlighted track
1136                                                 int64_t asset_length;
1137                                                 // we use video if we are over video and audio if we are over audio
1138                                                 if (asset->video_data && mwindow->session->track_highlighted->data_type == TRACK_VIDEO)
1139                                                         asset_length = mwindow->session->track_highlighted->to_units(asset->video_length / asset->frame_rate, 0);
1140                                                 else
1141                                                         asset_length = mwindow->session->track_highlighted->to_units(asset->audio_length / asset->sample_rate, 0);
1143                                                 position = mwindow->session->track_highlighted->from_units(get_drop_position(&insertion, NULL, asset_length));
1144                                                 if (position < 0) 
1145                                                         w = -1;
1146                                                 else
1147                                                 {
1148                                                         current_atrack++;
1149                                                         draw_box = 1;
1150                                                 }
1151                                         }
1152                                         else
1153                                         if(clip && current_atrack < clip->tracks->total_audio_tracks())
1154                                         {
1155                                                 w = Units::to_int64((double)clip->tracks->total_length() *
1156                                                         mwindow->edl->session->sample_rate / 
1157                                                         mwindow->edl->local_session->zoom_sample);
1158 //printf("draw_paste_destination %d\n", x);
1159                                                 int64_t asset_length = mwindow->session->track_highlighted->to_units((double)clip->tracks->total_length(), 0);
1160                                 
1161                                                 position = mwindow->session->track_highlighted->from_units(get_drop_position(&insertion, NULL, asset_length));
1162                                                 if (position < 0) 
1163                                                         w = -1;
1164                                                 else
1165                                                 {
1166                                                         current_atrack++;
1167                                                         draw_box = 1;
1168                                                 }
1169                                         }
1170                                         else
1171                                         if(mwindow->session->current_operation == DRAG_EDIT &&
1172                                                 current_aedit < mwindow->session->drag_edits->total)
1173                                         {
1174                                                 Edit *edit;
1175                                                 while(current_aedit < mwindow->session->drag_edits->total &&
1176                                                         mwindow->session->drag_edits->values[current_aedit]->track->data_type != TRACK_AUDIO)
1177                                                         current_aedit++;
1179                                                 if(current_aedit < mwindow->session->drag_edits->total)
1180                                                 {
1181                                                         edit = mwindow->session->drag_edits->values[current_aedit];
1182                                                         w = Units::to_int64(edit->length / mwindow->edl->local_session->zoom_sample);
1184                                                         position = mwindow->session->track_highlighted->from_units(get_drop_position(&insertion, mwindow->session->drag_edit, mwindow->session->drag_edit->length));
1185                                                         if (position < 0) 
1186                                                                 w = -1;
1187                                                         else
1188                                                         {
1189                                                                 current_aedit++;
1190                                                                 draw_box = 1;
1191                                                         }
1193                                                 }
1194                                         }
1195                                 }
1196                                 else
1197                                 if(dest->data_type == TRACK_VIDEO)
1198                                 {
1199 //printf("draw_paste_destination 1\n");
1200                                         if(asset && current_vtrack < asset->layers)
1201                                         {
1202                                                 w = Units::to_int64((double)asset->video_length / 
1203                                                         asset->frame_rate *
1204                                                         mwindow->edl->session->sample_rate /
1205                                                         mwindow->edl->local_session->zoom_sample);
1206                                                 int64_t asset_length = mwindow->session->track_highlighted->to_units((double)asset->video_length / 
1207                                                         asset->frame_rate, 0);
1208                                 
1209                                                 position = mwindow->session->track_highlighted->from_units(get_drop_position(&insertion, NULL, asset_length));
1210                                                 if (position < 0) 
1211                                                         w = -1;
1212                                                 else
1213                                                 {
1214                                                         current_vtrack++;
1215                                                         draw_box = 1;
1216                                                 }
1217                                         }
1218                                         else
1219                                         if(clip && current_vtrack < clip->tracks->total_video_tracks())
1220                                         {
1221                                                 w = Units::to_int64(clip->tracks->total_length() *
1222                                                         mwindow->edl->session->sample_rate / 
1223                                                         mwindow->edl->local_session->zoom_sample);
1224                                                 int64_t asset_length = mwindow->session->track_highlighted->to_units((double)clip->tracks->total_length(), 0);
1225                                 
1226                                                 position = mwindow->session->track_highlighted->from_units(get_drop_position(&insertion, NULL, asset_length));
1227                                                 if (position < 0) 
1228                                                         w = -1;
1229                                                 else
1230                                                 {
1231                                                         current_vtrack++;
1232                                                         draw_box = 1;
1233                                                 }
1234                                         }
1235                                         else
1236                                         if(mwindow->session->current_operation == DRAG_EDIT &&
1237                                                 current_vedit < mwindow->session->drag_edits->total)
1238                                         {
1239                                                 Edit *edit;
1240                                                 while(current_vedit < mwindow->session->drag_edits->total &&
1241                                                         mwindow->session->drag_edits->values[current_vedit]->track->data_type != TRACK_VIDEO)
1242                                                         current_vedit++;
1244                                                 if(current_vedit < mwindow->session->drag_edits->total)
1245                                                 {
1246                                                         edit = mwindow->session->drag_edits->values[current_vedit];
1247                                                         w = Units::to_int64(edit->track->from_units(edit->length) *
1248                                                                 mwindow->edl->session->sample_rate / 
1249                                                                 mwindow->edl->local_session->zoom_sample);
1251                                                         position = mwindow->session->track_highlighted->from_units(get_drop_position(&insertion, mwindow->session->drag_edit, mwindow->session->drag_edit->length));
1252                                                         if (position < 0) 
1253                                                                 w = -1;
1254                                                         else
1255                                                         {
1256                                                                 current_vedit++;
1257                                                                 draw_box = 1;
1258                                                         }
1259                                                 }
1261                                         }
1262                                 }
1264                                 if(w >= 0)
1265                                 {
1266 // Get the x coordinate
1267                                         x = Units::to_int64(position * 
1268                                                 mwindow->edl->session->sample_rate /
1269                                                 mwindow->edl->local_session->zoom_sample) - 
1270                                                 mwindow->edl->local_session->view_start;
1271                                         int y = dest->y_pixel;
1272                                         int h = dest->vertical_span(mwindow->theme);
1275 //printf("TrackCanvas::draw_paste_destination 2 %d %d %d %d\n", x, y, w, h);
1276                                         if (insertion)
1277                                                 draw_highlight_insertion(x, y, w, h);
1278                                         else
1279                                                 draw_highlight_rectangle(x, y, w, h);
1280                                         
1282                                 }
1283                         }
1284                 }
1285         }
1288 void TrackCanvas::plugin_dimensions(Plugin *plugin, int64_t &x, int64_t &y, int64_t &w, int64_t &h)
1290         x = Units::round(plugin->track->from_units(plugin->startproject) *
1291                 mwindow->edl->session->sample_rate / 
1292                 mwindow->edl->local_session->zoom_sample - 
1293                 mwindow->edl->local_session->view_start);
1294         w = Units::round(plugin->track->from_units(plugin->length) *
1295                 mwindow->edl->session->sample_rate / 
1296                 mwindow->edl->local_session->zoom_sample);
1297         y = plugin->track->y_pixel + 
1298                         mwindow->edl->local_session->zoom_track +
1299                         plugin->plugin_set->get_number() * 
1300                         mwindow->theme->plugin_bg_data->get_h();
1301         if(mwindow->edl->session->show_titles)
1302                 y += mwindow->theme->title_bg_data->get_h();
1303         h = mwindow->theme->plugin_bg_data->get_h();
1306 int TrackCanvas::resource_h()
1308         return mwindow->edl->local_session->zoom_track;
1311 void TrackCanvas::draw_highlight_rectangle(int x, int y, int w, int h)
1314 // if we have to draw a highlighted rectangle completely on the left or completely on the right of the viewport, 
1315 // just draw arrows, so user has indication that something is there
1316 // FIXME: get better colors
1318         if (x + w <= 0)
1319         {
1320                 draw_triangle_left(0, y + h /6, h * 2/3, h * 2/3, BLACK, GREEN, YELLOW, RED, BLUE);
1321                 return;
1322         } else
1323         if (x >= get_w())
1324         {
1325                 draw_triangle_right(get_w() - h * 2/3, y + h /6, h * 2/3, h * 2/3, BLACK, GREEN, YELLOW, RED, BLUE);
1326                 return;
1327         }
1329 // Fix bug in heroines & cvs version as of 22.8.2005:
1330 // If we grab when zoomed in and zoom out while dragging, when edit gets really narrow strange things start happening
1331         if (w >= 0 && w < 3) {x -= w /2; w = 3;};
1332         if(x < -10)
1333         {
1334                 w += x - -10;
1335                 x = -10;
1336         }
1337         if(y < -10)
1338         {
1339                 h += y - -10;
1340                 y = -10;
1341         }
1342         w = MIN(w, get_w() + 20);
1343         h = MIN(h, get_h() + 20);
1344         set_color(WHITE);
1345         set_inverse();
1346         draw_rectangle(x, y, w, h);
1347         draw_rectangle(x + 1, y + 1, w - 2, h - 2);
1348         set_opaque();
1349 //printf("TrackCanvas::draw_highlight_rectangle %d %d %d %d\n", x, y, w, h);
1352 void TrackCanvas::draw_highlight_insertion(int x, int y, int w, int h)
1355 // if we have to draw a highlighted rectangle completely on the left or completely on the right of the viewport, 
1356 // just draw arrows, so user has indication that something is there
1357 // FIXME: get better colors
1360         
1361         int h1 = h / 8;
1362         int h2 = h / 4;
1363         
1364         set_inverse();
1366 /* these don't look so good
1368         draw_line(x, y, x, y+h);
1369         draw_line(x - h2 * 2, y + h1*2,   x - h2, y+h1*2);
1370         draw_line(x - h2 * 2, y + h1*2+1, x - h2, y+h1*2+1);
1371         draw_line(x - h2 * 2, y + h1*6,   x - h2, y+h1*6);
1372         draw_line(x - h2 * 2, y + h1*6+1, x - h2, y+h1*6+1);
1374         draw_triangle_right(x - h2, y + h1, h2, h2, BLACK, GREEN, YELLOW, RED, BLUE);
1375         draw_triangle_right(x - h2, y + h1*5, h2, h2, BLACK, GREEN, YELLOW, RED, BLUE);
1377 /*      draw_line(x + h2 * 2, y + h1*2,   x + h2, y+h1*2);
1378         draw_line(x + h2 * 2, y + h1*2+1, x + h2, y+h1*2+1);
1379         draw_line(x + h2 * 2, y + h1*6,   x + h2, y+h1*6);
1380         draw_line(x - h2 * 2, y + h1*6+1, x + h2, y+h1*6+1);
1382         draw_triangle_left(x, y + h1, h2, h2, BLACK, GREEN, YELLOW, RED, BLUE);
1383         draw_triangle_left(x, y + h1*5, h2, h2, BLACK, GREEN, YELLOW, RED, BLUE);
1384         
1385 // draw the box centred around x
1386         x -= w / 2;
1387 // Fix bug in heroines & cvs version as of 22.8.2005:
1388 // If we grab when zoomed in and zoom out while dragging, when edit gets really narrow strange things start happening
1389         if (w >= 0 && w < 3) {x -= w /2; w = 3;};
1390         if(x < -10)
1391         {
1392                 w += x - -10;
1393                 x = -10;
1394         }
1395         if(y < -10)
1396         {
1397                 h += y - -10;
1398                 y = -10;
1399         }
1400         w = MIN(w, get_w() + 20);
1401         h = MIN(h, get_h() + 20);
1402         set_color(WHITE);
1403         set_inverse();
1404         draw_rectangle(x, y, w, h);
1405         draw_rectangle(x + 1, y + 1, w - 2, h - 2);
1406         set_opaque();
1407 //printf("TrackCanvas::draw_highlight_insertion %d %d %d %d\n", x, y, w, h);
1410 void TrackCanvas::draw_playback_cursor()
1412 // Called before playback_cursor exists
1413 //      if(mwindow->playback_cursor && mwindow->playback_cursor->visible)
1414 //      {
1415 //              mwindow->playback_cursor->visible = 0;
1416 //              mwindow->playback_cursor->draw();
1417 //      }
1420 void TrackCanvas::get_handle_coords(Edit *edit, int64_t &x, int64_t &y, int64_t &w, int64_t &h, int side)
1422         int handle_w = mwindow->theme->edithandlein_data[0]->get_w();
1423         int handle_h = mwindow->theme->edithandlein_data[0]->get_h();
1425         edit_dimensions(edit, x, y, w, h);
1427         if(mwindow->edl->session->show_titles)
1428         {
1429                 y += mwindow->theme->title_bg_data->get_h();
1430         }
1431         else
1432         {
1433                 y = 0;
1434         }
1436         if(side == EDIT_OUT)
1437         {
1438                 x += w - handle_w;
1439         }
1441         h = handle_h;
1442         w = handle_w;
1445 void TrackCanvas::get_transition_coords(int64_t &x, int64_t &y, int64_t &w, int64_t &h)
1447 //printf("TrackCanvas::get_transition_coords 1\n");
1448 //      int transition_w = mwindow->theme->transitionhandle_data[0]->get_w();
1449 //      int transition_h = mwindow->theme->transitionhandle_data[0]->get_h();
1450         int transition_w = 30;
1451         int transition_h = 30;
1452 //printf("TrackCanvas::get_transition_coords 1\n");
1454         if(mwindow->edl->session->show_titles)
1455                 y += mwindow->theme->title_bg_data->get_h();
1456 //printf("TrackCanvas::get_transition_coords 2\n");
1458         y += (h - mwindow->theme->title_bg_data->get_h()) / 2 - transition_h / 2;
1459         x -= transition_w / 2;
1461         h = transition_h;
1462         w = transition_w;
1465 void TrackCanvas::draw_highlighting()
1467         int64_t x, y, w, h;
1468         int draw_box = 0;
1473         switch(mwindow->session->current_operation)
1474         {
1475                 case DRAG_ATRANSITION:
1476                 case DRAG_VTRANSITION:
1477 //printf("TrackCanvas::draw_highlighting 1 %p %p\n", 
1478 //      mwindow->session->track_highlighted, mwindow->session->edit_highlighted);
1479                         if(mwindow->session->edit_highlighted)
1480                         {
1481 //printf("TrackCanvas::draw_highlighting 2\n");
1482                                 if((mwindow->session->current_operation == DRAG_ATRANSITION && 
1483                                         mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
1484                                         (mwindow->session->current_operation == DRAG_VTRANSITION && 
1485                                         mwindow->session->track_highlighted->data_type == TRACK_VIDEO))
1486                                 {
1487 //printf("TrackCanvas::draw_highlighting 2\n");
1488                                         edit_dimensions(mwindow->session->edit_highlighted, x, y, w, h);
1489 //printf("TrackCanvas::draw_highlighting 2\n");
1491                                         if(MWindowGUI::visible(x, x + w, 0, get_w()) &&
1492                                                 MWindowGUI::visible(y, y + h, 0, get_h()))
1493                                         {
1494                                                 draw_box = 1;
1495                                                 get_transition_coords(x, y, w, h);
1496                                         }
1497 //printf("TrackCanvas::draw_highlighting 3\n");
1498                                 }
1499                         }
1500                         break;
1504 // Dragging a new effect from the Resource window
1505                 case DRAG_AEFFECT:
1506                 case DRAG_VEFFECT:
1507                         if(mwindow->session->track_highlighted &&
1508                                 ((mwindow->session->current_operation == DRAG_AEFFECT && mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
1509                                         (mwindow->session->current_operation == DRAG_VEFFECT && mwindow->session->track_highlighted->data_type == TRACK_VIDEO)))
1510                         {
1511 // Put it before another plugin
1512                                 if(mwindow->session->plugin_highlighted)
1513                                 {
1514                                         plugin_dimensions(mwindow->session->plugin_highlighted, 
1515                                                 x, 
1516                                                 y, 
1517                                                 w, 
1518                                                 h);
1519 //printf("TrackCanvas::draw_highlighting 1 %d %d\n", x, w);
1520                                 }
1521                                 else
1522 // Put it after a plugin set
1523                                 if(mwindow->session->pluginset_highlighted &&
1524                                         mwindow->session->pluginset_highlighted->last)
1525                                 {
1526                                         plugin_dimensions((Plugin*)mwindow->session->pluginset_highlighted->last, 
1527                                                 x, 
1528                                                 y, 
1529                                                 w, 
1530                                                 h);
1531 //printf("TrackCanvas::draw_highlighting 1 %d %d\n", x, w);
1532                                         int64_t track_x, track_y, track_w, track_h;
1533                                         track_dimensions(mwindow->session->track_highlighted, 
1534                                                 track_x, 
1535                                                 track_y, 
1536                                                 track_w, 
1537                                                 track_h);
1539                                         x += w;
1540                                         w = Units::round(
1541                                                         mwindow->session->track_highlighted->get_length() *
1542                                                         mwindow->edl->session->sample_rate / 
1543                                                         mwindow->edl->local_session->zoom_sample - 
1544                                                         mwindow->edl->local_session->view_start) -
1545                                                 x;
1546 //printf("TrackCanvas::draw_highlighting 2 %d\n", w);
1547                                         if(w <= 0) w = track_w;
1548                                 }
1549                                 else
1550                                 {
1551                                         track_dimensions(mwindow->session->track_highlighted, 
1552                                                 x, 
1553                                                 y, 
1554                                                 w, 
1555                                                 h);
1557 //printf("TrackCanvas::draw_highlighting 1 %d %d %d %d\n", x, y, w, h);
1558 // Put it in a new plugin set determined by the selected range
1559                                         if(mwindow->edl->local_session->get_selectionend() > 
1560                                                 mwindow->edl->local_session->get_selectionstart())
1561                                         {
1562                                                 x = Units::to_int64(mwindow->edl->local_session->get_selectionstart() *
1563                                                         mwindow->edl->session->sample_rate / 
1564                                                         mwindow->edl->local_session->zoom_sample -
1565                                                         mwindow->edl->local_session->view_start);
1566                                                 w = Units::to_int64((mwindow->edl->local_session->get_selectionend() - 
1567                                                         mwindow->edl->local_session->get_selectionstart()) *
1568                                                         mwindow->edl->session->sample_rate / 
1569                                                         mwindow->edl->local_session->zoom_sample);
1570                                         }
1571 // Put it in a new plugin set determined by an edit boundary
1572                                         else
1573                                         if(mwindow->session->edit_highlighted)
1574                                         {
1575                                                 int64_t temp_y, temp_h;
1576                                                 edit_dimensions(mwindow->session->edit_highlighted, 
1577                                                         x, 
1578                                                         temp_y, 
1579                                                         w, 
1580                                                         temp_h);
1581                                         }
1582 // Put it at the beginning of the track in a new plugin set
1583                                 }
1585                                 if(MWindowGUI::visible(x, x + w, 0, get_w()) &&
1586                                         MWindowGUI::visible(y, y + h, 0, get_h()))
1587                                 {
1588 //printf("TrackCanvas::draw_highlighting 1\n");
1589                                         draw_box = 1;
1590                                 }
1591                         }
1592                         break;
1593                 
1594                 case DRAG_ASSET:
1595                         if(mwindow->session->track_highlighted)
1596                         {
1597                                 track_dimensions(mwindow->session->track_highlighted, x, y, w, h);
1599                                 if(MWindowGUI::visible(y, y + h, 0, get_h()))
1600                                 {
1601                                         draw_paste_destination();
1602                                 }
1603                         }
1604                         break;
1606 // Dragging an effect from the timeline
1607                 case DRAG_AEFFECT_COPY:
1608                 case DRAG_VEFFECT_COPY:
1609                         if((mwindow->session->plugin_highlighted || mwindow->session->track_highlighted) &&
1610                                 ((mwindow->session->current_operation == DRAG_AEFFECT_COPY && mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
1611                                 (mwindow->session->current_operation == DRAG_VEFFECT_COPY && mwindow->session->track_highlighted->data_type == TRACK_VIDEO)))
1612                         {
1613 // Put it before another plugin
1614                                 if(mwindow->session->plugin_highlighted)
1615                                         plugin_dimensions(mwindow->session->plugin_highlighted, x, y, w, h);
1616                                 else
1617 // Put it after a plugin set
1618                                 if(mwindow->session->pluginset_highlighted &&
1619                                         mwindow->session->pluginset_highlighted->last)
1620                                 {
1621                                         plugin_dimensions((Plugin*)mwindow->session->pluginset_highlighted->last, x, y, w, h);
1622                                         x += w;
1623                                 }
1624                                 else
1625                                 if(mwindow->session->track_highlighted)
1626                                 {
1627                                         track_dimensions(mwindow->session->track_highlighted, x, y, w, h);
1629 // Put it in a new plugin set determined by an edit boundary
1630                                         if(mwindow->session->edit_highlighted)
1631                                         {
1632                                                 int64_t temp_y, temp_h;
1633                                                 edit_dimensions(mwindow->session->edit_highlighted, 
1634                                                         x, 
1635                                                         temp_y, 
1636                                                         w, 
1637                                                         temp_h);
1638                                         }
1639 // Put it in a new plugin set at the start of the track
1640                                 }
1642 // Calculate length of plugin based on data type of track and units
1643                                 if(mwindow->session->track_highlighted->data_type == TRACK_VIDEO)
1644                                 {
1645                                         w = (int64_t)((double)mwindow->session->drag_plugin->length / 
1646                                                 mwindow->edl->session->frame_rate *
1647                                                 mwindow->edl->session->sample_rate /
1648                                                 mwindow->edl->local_session->zoom_sample);
1649                                 }
1650                                 else
1651                                 {
1652                                         w = (int64_t)mwindow->session->drag_plugin->length /
1653                                                 mwindow->edl->local_session->zoom_sample;
1654                                 }
1656                                 if(MWindowGUI::visible(x, x + w, 0, get_w()) &&
1657                                         MWindowGUI::visible(y, y + h, 0, get_h()))
1658                                 {
1659                                         draw_box = 1;
1660                                 }
1661                         }
1662                         break;
1664                 case DRAG_PLUGINKEY:
1665                         if(mwindow->session->plugin_highlighted && 
1666                            mwindow->session->current_operation == DRAG_PLUGINKEY)
1667                         {
1668 // Just highlight the plugin
1669                                 plugin_dimensions(mwindow->session->plugin_highlighted, x, y, w, h);
1671                                 if(MWindowGUI::visible(x, x + w, 0, get_w()) &&
1672                                         MWindowGUI::visible(y, y + h, 0, get_h()))
1673                                 {
1674                                         draw_box = 1;
1675                                 }
1676                         }
1677                         break;
1679                 case DRAG_EDIT:
1680                         if(mwindow->session->track_highlighted)
1681                         {
1682                                 track_dimensions(mwindow->session->track_highlighted, x, y, w, h);
1684                                 if(MWindowGUI::visible(y, y + h, 0, get_h()))
1685                                 {
1686                                         draw_paste_destination();
1687                                 }
1688                         }
1689                         break;
1690         }
1693         if(draw_box)
1694         {
1695                 draw_highlight_rectangle(x, y, w, h);
1696         }
1699 void TrackCanvas::draw_plugins()
1701         char string[BCTEXTLEN];
1703         if(!mwindow->edl->session->show_assets) return;
1705         for(Track *track = mwindow->edl->tracks->first;
1706                 track;
1707                 track = track->next)
1708         {
1709                 if(track->expand_view)
1710                 {
1711                         for(int i = 0; i < track->plugin_set.total; i++)
1712                         {
1713                                 PluginSet *pluginset = track->plugin_set.values[i];
1715                                 for(Plugin *plugin = (Plugin*)pluginset->first; plugin; plugin = (Plugin*)plugin->next)
1716                                 {
1717                                         int64_t total_x, y, total_w, h;
1718                                         plugin_dimensions(plugin, total_x, y, total_w, h);
1719                                         
1720                                         if(MWindowGUI::visible(total_x, total_x + total_w, 0, get_w()) &&
1721                                                 MWindowGUI::visible(y, y + h, 0, get_h()) &&
1722                                                 plugin->plugin_type != PLUGIN_NONE)
1723                                         {
1724                                                 int x = total_x, w = total_w, left_margin = 5;
1725                                                 if(x < 0)
1726                                                 {
1727                                                         w -= -x;
1728                                                         x = 0;
1729                                                 }
1730                                                 if(w + x > get_w()) w -= (w + x) - get_w();
1732                                                 draw_3segmenth(x, 
1733                                                         y, 
1734                                                         w, 
1735                                                         total_x,
1736                                                         total_w,
1737                                                         mwindow->theme->plugin_bg_data,
1738                                                         0);
1739                                                 set_color(WHITE);
1740                                                 set_font(MEDIUMFONT_3D);
1741                                                 plugin->calculate_title(string, 0);
1743 // Truncate string to int64_test visible in background
1744                                                 int len = strlen(string), j;
1745                                                 for(j = len; j >= 0; j--)
1746                                                 {
1747                                                         if(left_margin + get_text_width(MEDIUMFONT_3D, string) > w)
1748                                                         {
1749                                                                 string[j] = 0;
1750                                                         }
1751                                                         else
1752                                                                 break;
1753                                                 }
1755 // Justify the text on the left boundary of the edit if it is visible.
1756 // Otherwise justify it on the left side of the screen.
1757                                                 int text_x = total_x + left_margin;
1758                                                 text_x = MAX(left_margin, text_x);
1759                                                 draw_text(text_x, 
1760                                                         y + get_text_ascent(MEDIUMFONT_3D) + 2, 
1761                                                         string,
1762                                                         strlen(string),
1763                                                         0);
1764                                         }
1765                                 }
1766                         }
1767                 }
1768         }
1772 void TrackCanvas::draw_inout_points()
1777 void TrackCanvas::draw_drag_handle()
1779         if(mwindow->session->current_operation == DRAG_EDITHANDLE2 ||
1780                 mwindow->session->current_operation == DRAG_PLUGINHANDLE2)
1781         {
1782 //printf("TrackCanvas::draw_drag_handle 1 %ld %ld\n", mwindow->session->drag_sample, mwindow->edl->local_session->view_start);
1783                 int64_t pixel1 = Units::round(mwindow->session->drag_position * 
1784                         mwindow->edl->session->sample_rate /
1785                         mwindow->edl->local_session->zoom_sample - 
1786                         mwindow->edl->local_session->view_start);
1787 //printf("TrackCanvas::draw_drag_handle 2 %d\n", pixel1);
1788                 set_color(GREEN);
1789                 set_inverse();
1790 //printf("TrackCanvas::draw_drag_handle 3\n");
1791                 draw_line(pixel1, 0, pixel1, get_h());
1792                 set_opaque();
1793 //printf("TrackCanvas::draw_drag_handle 4\n");
1794         }
1798 void TrackCanvas::draw_transitions()
1800         int64_t x, y, w, h;
1802         if(!mwindow->edl->session->show_assets) return;
1804         for(Track *track = mwindow->edl->tracks->first;
1805                 track;
1806                 track = track->next)
1807         {
1808                 for(Edit *edit = track->edits->first;
1809                         edit;
1810                         edit = edit->next)
1811                 {
1812                         if(edit->transition)
1813                         {
1814                                 int64_t strip_w, strip_x, strip_y;
1815                                 edit_dimensions(edit, x, y, w, h);
1816                                 strip_x = x ;
1817                                 strip_y = y;
1818                                 if(mwindow->edl->session->show_titles)
1819                                         strip_y += mwindow->theme->title_bg_data->get_h();
1821                                 get_transition_coords(x, y, w, h);
1822                                 strip_w = Units::round(edit->track->from_units(edit->transition->length) * 
1823                                         mwindow->edl->session->sample_rate / 
1824                                         mwindow->edl->local_session->zoom_sample);
1826                                 if(MWindowGUI::visible(x, x + w, 0, get_w()) &&
1827                                         MWindowGUI::visible(y, y + h, 0, get_h()))
1828                                 {
1829                                         PluginServer *server = mwindow->scan_plugindb(edit->transition->title,
1830                                                 track->data_type);
1831                                         draw_vframe(server->picon, 
1832                                                 x, 
1833                                                 y, 
1834                                                 w, 
1835                                                 h, 
1836                                                 0, 
1837                                                 0, 
1838                                                 server->picon->get_w(), 
1839                                                 server->picon->get_h());
1840                                 }
1841                                 if(MWindowGUI::visible(strip_x, strip_x + strip_w, 0, get_w()) &&
1842                                         MWindowGUI::visible(strip_y, strip_y + h, 0, get_h()))
1843                                 {
1844                                         int x = strip_x, w = strip_w, left_margin = 5;
1845                                         if(x < 0)
1846                                         {
1847                                                 w -= -x;
1848                                                 x = 0;
1849                                         }
1850                                         if(w + x > get_w()) w -= (w + x) - get_w();
1851                                 
1852                                         draw_3segmenth(
1853                                                 x, 
1854                                                 strip_y, 
1855                                                 w, 
1856                                                 strip_x,
1857                                                 strip_w,
1858                                                 mwindow->theme->plugin_bg_data,
1859                                                 0);
1861                                 }
1862                         }
1863                 }
1864         }
1867 void TrackCanvas::draw_loop_points()
1869 //printf("TrackCanvas::draw_loop_points 1\n");
1870         if(mwindow->edl->local_session->loop_playback)
1871         {
1872 //printf("TrackCanvas::draw_loop_points 2\n");
1873                 int64_t x = Units::round(mwindow->edl->local_session->loop_start *
1874                         mwindow->edl->session->sample_rate /
1875                         mwindow->edl->local_session->zoom_sample - 
1876                         mwindow->edl->local_session->view_start);
1877 //printf("TrackCanvas::draw_loop_points 3\n");
1879                 if(MWindowGUI::visible(x, x + 1, 0, get_w()))
1880                 {
1881                         set_color(GREEN);
1882                         draw_line(x, 0, x, get_h());
1883                 }
1884 //printf("TrackCanvas::draw_loop_points 4\n");
1886                 x = Units::round(mwindow->edl->local_session->loop_end *
1887                         mwindow->edl->session->sample_rate /
1888                         mwindow->edl->local_session->zoom_sample - 
1889                         mwindow->edl->local_session->view_start);
1890 //printf("TrackCanvas::draw_loop_points 5\n");
1892                 if(MWindowGUI::visible(x, x + 1, 0, get_w()))
1893                 {
1894                         set_color(GREEN);
1895                         draw_line(x, 0, x, get_h());
1896                 }
1897 //printf("TrackCanvas::draw_loop_points 6\n");
1898         }
1899 //printf("TrackCanvas::draw_loop_points 7\n");
1902 void TrackCanvas::draw_brender_start()
1904         if(mwindow->preferences->use_brender)
1905         {
1906                 int64_t x = Units::round(mwindow->edl->session->brender_start *
1907                         mwindow->edl->session->sample_rate /
1908                         mwindow->edl->local_session->zoom_sample - 
1909                         mwindow->edl->local_session->view_start);
1911                 if(MWindowGUI::visible(x, x + 1, 0, get_w()))
1912                 {
1913                         set_color(RED);
1914                         draw_line(x, 0, x, get_h());
1915                 }
1916         }
1919 static int auto_colors[] = 
1921         BLUE,
1922         RED,
1923         GREEN,
1924         BLUE,
1925         RED,
1926         GREEN,
1927         BLUE,
1928         WHITE,
1929         0,
1930         0,
1931         0,
1932         0
1935 // The operations which correspond to each automation type
1936 static int auto_operations[] = 
1938         DRAG_MUTE,
1939         DRAG_CAMERA_X,
1940         DRAG_CAMERA_Y,
1941         DRAG_CAMERA_Z,
1942         DRAG_PROJECTOR_X,
1943         DRAG_PROJECTOR_Y,
1944         DRAG_PROJECTOR_Z,
1945         DRAG_FADE,
1946         DRAG_PAN,
1947         DRAG_MODE,
1948         DRAG_MASK,
1949         DRAG_NUDGE
1952 // The buttonpress operations, so nothing changes unless the mouse moves
1953 // a certain amount.  This allows the keyframe to be used to position the
1954 // insertion point without moving itself.
1955 static int pre_auto_operations[] =
1957         DRAG_MUTE,
1958         DRAG_CAMERA_X,
1959         DRAG_CAMERA_Y,
1960         DRAG_CAMERA_Z,
1961         DRAG_PROJECTOR_X,
1962         DRAG_PROJECTOR_Y,
1963         DRAG_PROJECTOR_Z,
1964         DRAG_FADE,
1965         DRAG_PAN_PRE,
1966         DRAG_MODE_PRE,
1967         DRAG_MASK_PRE,
1968         DRAG_NUDGE
1972 int TrackCanvas::do_keyframes(int cursor_x, 
1973         int cursor_y, 
1974         int draw, 
1975         int buttonpress, 
1976         int &new_cursor,
1977         int &update_cursor,
1978         int &rerender)
1980 // Note: button 3 (right mouse button) is not eaten to allow
1981 // track context menu to appear
1982         int current_tool = 0;
1983         int result = 0;
1984         EDLSession *session = mwindow->edl->session;
1987         if(buttonpress == 3)
1988         {
1989                 update_cursor = 1;
1990                 return 0;
1991         }
1995         BC_Pixmap *auto_pixmaps[] = 
1996         {
1997                 0,
1998                 0,
1999                 0,
2000                 0,
2001                 0,
2002                 0,
2003                 0,
2004                 0,
2005                 pankeyframe_pixmap,
2006                 modekeyframe_pixmap,
2007                 maskkeyframe_pixmap,
2008                 0,
2009         };
2013         for(Track *track = mwindow->edl->tracks->first;
2014                 track && !result;
2015                 track = track->next)
2016         {
2017                 Auto *auto_keyframe;
2018                 Automation *automation = track->automation;
2021 // Handle float autos
2022                 for(int i = 0; i < AUTOMATION_TOTAL && !result; i++)
2023                 {
2024 // Event not trapped and automation visible
2025                         Autos *autos = automation->autos[i];
2026                         if(!result && session->auto_conf->autos[i] && autos)
2027                         {
2028                                 switch(i)
2029                                 {
2030                                         case AUTOMATION_MODE:
2031                                                 result = do_autos(track, 
2032                                                         automation->autos[i],
2033                                                         cursor_x, 
2034                                                         cursor_y, 
2035                                                         draw, 
2036                                                         buttonpress,
2037                                                         auto_pixmaps[i],
2038                                                         auto_keyframe);
2039                                                 break;
2041                                         default:
2042                                                 switch(autos->get_type())
2043                                                 {
2044                                                         case AUTOMATION_TYPE_FLOAT:
2045                                                                 result = do_float_autos(track, 
2046                                                                         autos,
2047                                                                         cursor_x, 
2048                                                                         cursor_y, 
2049                                                                         draw, 
2050                                                                         buttonpress, 
2051                                                                         auto_colors[i],
2052                                                                         auto_keyframe);
2053                                                                 break;
2055                                                         case AUTOMATION_TYPE_INT:
2056                                                                 result = do_toggle_autos(track, 
2057                                                                         autos,
2058                                                                         cursor_x, 
2059                                                                         cursor_y, 
2060                                                                         draw, 
2061                                                                         buttonpress,
2062                                                                         auto_colors[i],
2063                                                                         auto_keyframe);
2064                                                                 break;
2065                                                 }
2066                                                 break;
2067                                 }
2068                         
2071                                 if(result)
2072                                 {
2073                                         if(mwindow->session->current_operation == auto_operations[i])
2074                                                 rerender = 1;
2075                                         if(buttonpress)
2076                                         {
2077                                                 if(i == AUTOMATION_FADE) 
2078                                                         synchronize_autos(0, 
2079                                                                 track, 
2080                                                                 (FloatAuto*)mwindow->session->drag_auto, 
2081                                                                 1);
2082                                                 mwindow->session->current_operation = pre_auto_operations[i];
2083                                                 update_drag_caption();
2084                                         }
2085                                 }
2086                         }
2087                 }
2092                 if(!result && 
2093                         session->auto_conf->plugins &&
2094                         mwindow->edl->session->show_assets)
2095                 {
2096                         Plugin *plugin;
2097                         KeyFrame *keyframe;
2098                         result = do_plugin_autos(track,
2099                                 cursor_x, 
2100                                 cursor_y, 
2101                                 draw, 
2102                                 buttonpress,
2103                                 plugin,
2104                                 keyframe);
2105                         if(result && mwindow->session->current_operation == DRAG_PLUGINKEY)
2106                         {
2107                                 rerender = 1;
2108                         }
2109                         if(result && (buttonpress == 1))
2110                         {
2111                                 mwindow->session->current_operation = DRAG_PLUGINKEY_PRE;
2112                                 update_drag_caption();
2113                                 rerender = 1;
2114                         } else
2115                         if (result && (buttonpress == 3))
2116                         {
2117                                 gui->keyframe_menu->update(plugin, keyframe);
2118                                 gui->keyframe_menu->activate_menu();
2119                                 rerender = 1; // the position changes
2120                         }
2121                 }
2122         }
2124 // Final pass to trap event
2125         for(int i = 0; i < AUTOMATION_TOTAL; i++)
2126         {
2127                 if(mwindow->session->current_operation == pre_auto_operations[i] ||
2128                         mwindow->session->current_operation == auto_operations[i])
2129                         result = 1;
2130         }
2132         if(mwindow->session->current_operation == DRAG_PLUGINKEY ||
2133                 mwindow->session->current_operation == DRAG_PLUGINKEY_PRE)
2134         {
2135                 result = 1;
2136         }
2138         update_cursor = 1;
2139         if(result)
2140         {
2141                 new_cursor = UPRIGHT_ARROW_CURSOR;
2142         }
2144         return result;
2147 void TrackCanvas::draw_auto(Auto *current, 
2148         int x, 
2149         int y, 
2150         int center_pixel, 
2151         int zoom_track,
2152         int color)
2154         int x1, y1, x2, y2;
2155         char string[BCTEXTLEN];
2157         x1 = x - HANDLE_W / 2;
2158         x2 = x + HANDLE_W / 2;
2159         y1 = center_pixel + y - HANDLE_W / 2;
2160         y2 = center_pixel + y + HANDLE_W / 2;
2162         if(y1 < center_pixel + -zoom_track / 2) y1 = center_pixel + -zoom_track / 2;
2163         if(y2 > center_pixel + zoom_track / 2) y2 = center_pixel + zoom_track / 2;
2165         set_color(BLACK);
2166         draw_box(x1 + 1, y1 + 1, x2 - x1, y2 - y1);
2167         set_color(color);
2168         draw_box(x1, y1, x2 - x1, y2 - y1);
2171 void TrackCanvas::draw_floatauto(Auto *current, 
2172         int x, 
2173         int y, 
2174         int in_x, 
2175         int in_y, 
2176         int out_x, 
2177         int out_y, 
2178         int center_pixel, 
2179         int zoom_track,
2180         int color)
2182         int x1, y1, x2, y2;
2183         int in_x1, in_y1, in_x2, in_y2;
2184         int out_x1, out_y1, out_x2, out_y2;
2185         char string[BCTEXTLEN];
2187 // Center
2188         x1 = x - HANDLE_W / 2;
2189         x2 = x + HANDLE_W / 2;
2190         y1 = center_pixel + y - HANDLE_W / 2;
2191         y2 = center_pixel + y + HANDLE_W / 2;
2193         CLAMP(y1, center_pixel + -zoom_track / 2, center_pixel + zoom_track / 2);
2194         CLAMP(y2, center_pixel + -zoom_track / 2, center_pixel + zoom_track / 2);
2196         if(y2 - 1 > y1)
2197         {
2198                 set_color(BLACK);
2199                 draw_box(x1 + 1, y1 + 1, x2 - x1, y2 - y1);
2200                 set_color(color);
2201                 draw_box(x1, y1, x2 - x1, y2 - y1);
2202         }
2204 // In handle
2205         in_x1 = in_x - HANDLE_W / 2;
2206         in_x2 = in_x + HANDLE_W / 2;
2207         in_y1 = center_pixel + in_y - HANDLE_W / 2;
2208         in_y2 = center_pixel + in_y + HANDLE_W / 2;
2210         CLAMP(in_y1, center_pixel + -zoom_track / 2, center_pixel + zoom_track / 2);
2211         CLAMP(in_y2, center_pixel + -zoom_track / 2, center_pixel + zoom_track / 2);
2212         CLAMP(in_y, -zoom_track / 2, zoom_track / 2);
2214         if(in_y2 > in_y1)
2215         {
2216                 set_color(BLACK);
2217                 draw_line(x + 1, center_pixel + y + 1, in_x + 1, center_pixel + in_y + 1);
2218                 draw_box(in_x1 + 1, in_y1 + 1, in_x2 - in_x1, in_y2 - in_y1);
2219                 set_color(color);
2220                 draw_line(x, center_pixel + y, in_x, center_pixel + in_y);
2221                 draw_box(in_x1, in_y1, in_x2 - in_x1, in_y2 - in_y1);
2222         }
2225 // Out handle
2226         out_x1 = out_x - HANDLE_W / 2;
2227         out_x2 = out_x + HANDLE_W / 2;
2228         out_y1 = center_pixel + out_y - HANDLE_W / 2;
2229         out_y2 = center_pixel + out_y + HANDLE_W / 2;
2231         CLAMP(out_y1, center_pixel + -zoom_track / 2, center_pixel + zoom_track / 2);
2232         CLAMP(out_y2, center_pixel + -zoom_track / 2, center_pixel + zoom_track / 2);
2233         CLAMP(out_y, -zoom_track / 2, zoom_track / 2);
2235         if(out_y2 > out_y1)
2236         {
2237                 set_color(BLACK);
2238                 draw_line(x + 1, center_pixel + y + 1, out_x + 1, center_pixel + out_y + 1);
2239                 draw_box(out_x1 + 1, out_y1 + 1, out_x2 - out_x1, out_y2 - out_y1);
2240                 set_color(color);
2241                 draw_line(x, center_pixel + y, out_x, center_pixel + out_y);
2242                 draw_box(out_x1, out_y1, out_x2 - out_x1, out_y2 - out_y1);
2243         }
2246 int TrackCanvas::test_auto(Auto *current, 
2247         int x, 
2248         int y, 
2249         int center_pixel, 
2250         int zoom_track, 
2251         int cursor_x, 
2252         int cursor_y, 
2253         int buttonpress)
2255         int x1, y1, x2, y2;
2256         char string[BCTEXTLEN];
2257         int result = 0;
2259         x1 = x - HANDLE_W / 2;
2260         x2 = x + HANDLE_W / 2;
2261         y1 = center_pixel + y - HANDLE_W / 2;
2262         y2 = center_pixel + y + HANDLE_W / 2;
2264         if(y1 < center_pixel + -zoom_track / 2) y1 = center_pixel + -zoom_track / 2;
2265         if(y2 > center_pixel + zoom_track / 2) y2 = center_pixel + zoom_track / 2;
2267         if(cursor_x >= x1 && cursor_x < x2 && cursor_y >= y1 && cursor_y < y2)
2268         {
2269                 if(buttonpress)
2270                 {
2271                         mwindow->session->drag_auto = current;
2272                         mwindow->session->drag_start_percentage = current->value_to_percentage();
2273                         mwindow->session->drag_start_position = current->position;
2274                         mwindow->session->drag_origin_x = cursor_x;
2275                         mwindow->session->drag_origin_y = cursor_y;
2276                 }
2277                 result = 1;
2278         }
2280         return result;
2283 int TrackCanvas::test_floatauto(Auto *current, 
2284         int x, 
2285         int y, 
2286         int in_x,
2287         int in_y,
2288         int out_x,
2289         int out_y,
2290         int center_pixel, 
2291         int zoom_track, 
2292         int cursor_x, 
2293         int cursor_y, 
2294         int buttonpress)
2296         int x1, y1, x2, y2;
2297         int in_x1, in_y1, in_x2, in_y2;
2298         int out_x1, out_y1, out_x2, out_y2;
2299         char string[BCTEXTLEN];
2300         int result = 0;
2302         x1 = x - HANDLE_W / 2;
2303         x2 = x + HANDLE_W / 2;
2304         y1 = center_pixel + y - HANDLE_W / 2;
2305         y2 = center_pixel + y + HANDLE_W / 2;
2307         if(y1 < center_pixel + -zoom_track / 2) y1 = center_pixel + -zoom_track / 2;
2308         if(y2 > center_pixel + zoom_track / 2) y2 = center_pixel + zoom_track / 2;
2310         in_x1 = in_x - HANDLE_W / 2;
2311         in_x2 = in_x + HANDLE_W / 2;
2312         in_y1 = center_pixel + in_y - HANDLE_W / 2;
2313         in_y2 = center_pixel + in_y + HANDLE_W / 2;
2315         if(in_y1 < center_pixel + -zoom_track / 2) in_y1 = center_pixel + -zoom_track / 2;
2316         if(in_y2 > center_pixel + zoom_track / 2) in_y2 = center_pixel + zoom_track / 2;
2318         out_x1 = out_x - HANDLE_W / 2;
2319         out_x2 = out_x + HANDLE_W / 2;
2320         out_y1 = center_pixel + out_y - HANDLE_W / 2;
2321         out_y2 = center_pixel + out_y + HANDLE_W / 2;
2323         if(out_y1 < center_pixel + -zoom_track / 2) out_y1 = center_pixel + -zoom_track / 2;
2324         if(out_y2 > center_pixel + zoom_track / 2) out_y2 = center_pixel + zoom_track / 2;
2328 //printf("TrackCanvas::test_floatauto %d %d %d %d %d %d\n", cursor_x, cursor_y, x1, x2, y1, y2);
2329 // Test value
2330         if(!ctrl_down() &&
2331                 cursor_x >= x1 && 
2332                 cursor_x < x2 && 
2333                 cursor_y >= y1 && 
2334                 cursor_y < y2)
2335         {
2336                 if(buttonpress && (buttonpress != 3))
2337                 {
2338                         mwindow->session->drag_auto = current;
2339                         mwindow->session->drag_start_percentage = current->value_to_percentage();
2340                         mwindow->session->drag_start_position = current->position;
2341                         mwindow->session->drag_origin_x = cursor_x;
2342                         mwindow->session->drag_origin_y = cursor_y;
2343                         mwindow->session->drag_handle = 0;
2344                 }
2345                 result = 1;
2346         }
2347         else
2348 // Test in control
2349         if(ctrl_down() &&
2350                 cursor_x >= in_x1 && 
2351                 cursor_x < in_x2 && 
2352                 cursor_y >= in_y1 && 
2353                 cursor_y < in_y2 &&
2354                 current->position > 0)
2355         {
2356                 if(buttonpress && (buttonpress != 3))
2357                 {
2358                         mwindow->session->drag_auto = current;
2359                         mwindow->session->drag_start_percentage = 
2360                                 current->invalue_to_percentage();
2361                         mwindow->session->drag_start_position = 
2362                                 ((FloatAuto*)current)->control_in_position;
2363                         mwindow->session->drag_origin_x = cursor_x;
2364                         mwindow->session->drag_origin_y = cursor_y;
2365                         mwindow->session->drag_handle = 1;
2366                 }
2367                 result = 1;
2368         }
2369         else
2370 // Test out control
2371         if(ctrl_down() &&
2372                 cursor_x >= out_x1 && 
2373                 cursor_x < out_x2 && 
2374                 cursor_y >= out_y1 && 
2375                 cursor_y < out_y2)
2376         {
2377                 if(buttonpress && (buttonpress != 3))
2378                 {
2379                         mwindow->session->drag_auto = current;
2380                         mwindow->session->drag_start_percentage = 
2381                                 current->outvalue_to_percentage();
2382                         mwindow->session->drag_start_position = 
2383                                 ((FloatAuto*)current)->control_out_position;
2384                         mwindow->session->drag_origin_x = cursor_x;
2385                         mwindow->session->drag_origin_y = cursor_y;
2386                         mwindow->session->drag_handle = 2;
2387                 }
2388                 result = 1;
2389         }
2391 // if(buttonpress) 
2392 // 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", 
2393 // mwindow->session->drag_handle,
2394 // ctrl_down(),
2395 // cursor_x,
2396 // cursor_y,
2397 // x1, x2, y1, y2);
2399         return result;
2402 void TrackCanvas::draw_floatline(int center_pixel, 
2403         FloatAuto *previous,
2404         FloatAuto *next,
2405         FloatAutos *autos,
2406         double unit_start,
2407         double zoom_units,
2408         double yscale,
2409         int x1,
2410         int y1,
2411         int x2,
2412         int y2,
2413         int color)
2415 // Solve bezier equation for either every pixel or a certain large number of
2416 // points.
2420 // Not using slope intercept
2421         x1 = MAX(0, x1);
2426         int prev_y;
2427 // Call by reference fails for some reason here
2428         FloatAuto *previous1 = previous, *next1 = next;
2429         float automation_min = mwindow->edl->local_session->automation_min;
2430         float automation_max = mwindow->edl->local_session->automation_max;
2431         float automation_range = automation_max - automation_min;
2433         for(int x = x1; x < x2; x++)
2434         {
2435                 int64_t position = (int64_t)(unit_start + x * zoom_units);
2436                 float value = autos->get_value(position, PLAY_FORWARD, previous1, next1);
2438                 int y = center_pixel + 
2439                         (int)(((value - automation_min) / automation_range - 0.5) * -yscale);
2441                 if(x > x1 && 
2442                         y >= center_pixel - yscale / 2 && 
2443                         y < center_pixel + yscale / 2 - 1)
2444                 {
2445                         set_color(BLACK);
2446                         draw_line(x - 1, prev_y + 1, x, y + 1);
2447                         set_color(color);
2448                         draw_line(x - 1, prev_y, x, y);
2449                 }
2450                 prev_y = y;
2451         }
2456 void TrackCanvas::synchronize_autos(float change, 
2457         Track *skip, 
2458         FloatAuto *fauto, 
2459         int fill_gangs)
2461 // fill mwindow->session->drag_auto_gang
2462         if (fill_gangs == 1 && skip->gang)
2463         {
2464                 for(Track *current = mwindow->edl->tracks->first;
2465                         current;
2466                         current = NEXT)
2467                 {
2468                         if(current->data_type == skip->data_type &&
2469                                 current->gang && 
2470                                 current->record && 
2471                                 current != skip)
2472                         {
2473                                 FloatAutos *fade_autos = (FloatAutos*)current->automation->autos[AUTOMATION_FADE];
2474                                 double position = skip->from_units(fauto->position);
2475                                 FloatAuto *previous = 0, *next = 0;
2477                                 float init_value = fade_autos->get_value(fauto->position, PLAY_FORWARD, previous, next);
2478                                 FloatAuto *keyframe;
2479                                 keyframe = (FloatAuto*)fade_autos->get_auto_at_position(position);
2480                                 
2481                                 if (!keyframe)
2482                                 {
2483 // create keyframe at exactly this point in time
2484                                         keyframe = (FloatAuto*)fade_autos->insert_auto(fauto->position);
2485                                         keyframe->value = init_value;
2486                                 } 
2487                                 else
2488                                 { 
2489 // keyframe exists, just change it
2490                                         keyframe->value += change;              
2491                                 } 
2492                                 
2493                                 keyframe->position = fauto->position;
2494                                 keyframe->control_out_position = fauto->control_out_position;
2495                                 keyframe->control_in_position = fauto->control_in_position;
2496                                 keyframe->control_out_value = fauto->control_out_value;
2497                                 keyframe->control_in_value = fauto->control_in_value;
2499                                 mwindow->session->drag_auto_gang->append((Auto *)keyframe);
2500                         }
2501                 }
2502         } else 
2503 // move the gangs
2504         if (fill_gangs == 0)      
2505         {
2506 // Move the gang!
2507                 for (int i = 0; i < mwindow->session->drag_auto_gang->total; i++)
2508                 {
2509                         FloatAuto *keyframe = (FloatAuto *)mwindow->session->drag_auto_gang->values[i];
2510                         
2511                         keyframe->value += change;
2512                         keyframe->position = fauto->position;
2513                         if(skip->data_type == TRACK_AUDIO)
2514                                 CLAMP(keyframe->value, INFINITYGAIN, MAX_AUDIO_FADE);
2515                         else
2516                                 CLAMP(keyframe->value, 0, MAX_VIDEO_FADE);
2517                         keyframe->control_out_position = fauto->control_out_position;
2518                         keyframe->control_in_position = fauto->control_in_position;
2519                         keyframe->control_out_value = fauto->control_out_value;
2520                         keyframe->control_in_value = fauto->control_in_value;
2521                 } 
2523         } 
2524         else
2525 // remove the gangs
2526         if (fill_gangs == -1)      
2527         {
2528                 for (int i = 0; i < mwindow->session->drag_auto_gang->total; i++)
2529                 {
2530                         FloatAuto *keyframe = (FloatAuto *)mwindow->session->drag_auto_gang->values[i];
2531                         keyframe->autos->remove_nonsequential(
2532                                         keyframe);
2533                 } 
2534                 mwindow->session->drag_auto_gang->remove_all();
2535         }
2539 int TrackCanvas::test_floatline(int center_pixel, 
2540                 FloatAutos *autos,
2541                 double unit_start,
2542                 double zoom_units,
2543                 double yscale,
2544                 int x1,
2545                 int x2,
2546                 int cursor_x, 
2547                 int cursor_y, 
2548                 int buttonpress)
2550         int result = 0;
2553         float automation_min = mwindow->edl->local_session->automation_min;
2554         float automation_max = mwindow->edl->local_session->automation_max;
2555         float automation_range = automation_max - automation_min;
2556         int64_t position = (int64_t)(unit_start + cursor_x * zoom_units);
2557 // Call by reference fails for some reason here
2558         FloatAuto *previous = 0, *next = 0;
2559         float value = autos->get_value(position, PLAY_FORWARD, previous, next);
2560         int y = center_pixel + 
2561                 (int)(((value - automation_min) / automation_range - 0.5) * -yscale);
2563         if(cursor_x >= x1 && 
2564                 cursor_x < x2 &&
2565                 cursor_y >= y - HANDLE_W / 2 && 
2566                 cursor_y < y + HANDLE_W / 2 &&
2567                 !ctrl_down())
2568         {
2569                 result = 1;
2572                 if(buttonpress)
2573                 {
2576                         Auto *current;
2577                         current = mwindow->session->drag_auto = autos->insert_auto(position);
2578                         ((FloatAuto*)current)->value = value;
2579                         mwindow->session->drag_start_percentage = current->value_to_percentage();
2580                         mwindow->session->drag_start_position = current->position;
2581                         mwindow->session->drag_origin_x = cursor_x;
2582                         mwindow->session->drag_origin_y = cursor_y;
2583                         mwindow->session->drag_handle = 0;
2585                 }
2586         }
2589         return result;
2592 void TrackCanvas::draw_toggleline(int center_pixel, 
2593         int x1,
2594         int y1,
2595         int x2,
2596         int y2,
2597         int color)
2599         set_color(BLACK);
2600         draw_line(x1, center_pixel + y1 + 1, x2, center_pixel + y1 + 1);
2601         set_color(color);
2602         draw_line(x1, center_pixel + y1, x2, center_pixel + y1);
2604         if(y2 != y1)
2605         {
2606                 set_color(BLACK);
2607                 draw_line(x2 + 1, center_pixel + y1, x2 + 1, center_pixel + y2);
2608                 set_color(color);
2609                 draw_line(x2, center_pixel + y1, x2, center_pixel + y2);
2610         }
2613 int TrackCanvas::test_toggleline(Autos *autos,
2614         int center_pixel, 
2615         int x1,
2616         int y1,
2617         int x2,
2618         int y2, 
2619         int cursor_x, 
2620         int cursor_y, 
2621         int buttonpress)
2623         int result = 0;
2624         if(cursor_x >= x1 && cursor_x < x2)
2625         {
2626                 int miny = center_pixel + y1 - HANDLE_W / 2;
2627                 int maxy = center_pixel + y1 + HANDLE_W / 2;
2628                 if(cursor_y >= miny && cursor_y < maxy) 
2629                 {
2630                         result = 1;
2632                         if(buttonpress)
2633                         {
2636                                 Auto *current;
2637                                 double position = (double)(cursor_x +
2638                                                 mwindow->edl->local_session->view_start) * 
2639                                         mwindow->edl->local_session->zoom_sample / 
2640                                         mwindow->edl->session->sample_rate;
2641                                 int64_t unit_position = autos->track->to_units(position, 0);
2642                                 int new_value = (int)((IntAutos*)autos)->get_automation_constant(unit_position, unit_position);
2644                                 current = mwindow->session->drag_auto = autos->insert_auto(unit_position);
2645                                 ((IntAuto*)current)->value = new_value;
2646                                 mwindow->session->drag_start_percentage = current->value_to_percentage();
2647                                 mwindow->session->drag_start_position = current->position;
2648                                 mwindow->session->drag_origin_x = cursor_x;
2649                                 mwindow->session->drag_origin_y = cursor_y;
2651                         }
2652                 }
2653         };
2654         return result;
2657 void TrackCanvas::calculate_viewport(Track *track, 
2658         double &view_start,   // Seconds
2659         double &unit_start,
2660         double &view_end,     // Seconds
2661         double &unit_end,
2662         double &yscale,
2663         int &center_pixel,
2664         double &zoom_sample,
2665         double &zoom_units)
2667         view_start = (double)mwindow->edl->local_session->view_start * 
2668                 mwindow->edl->local_session->zoom_sample /
2669                 mwindow->edl->session->sample_rate;
2670         unit_start = track->to_doubleunits(view_start);
2671         view_end = (double)(mwindow->edl->local_session->view_start + 
2672                 get_w()) * 
2673                 mwindow->edl->local_session->zoom_sample / 
2674                 mwindow->edl->session->sample_rate;
2675         unit_end = track->to_doubleunits(view_end);
2676         yscale = mwindow->edl->local_session->zoom_track;
2677         center_pixel = (int)(track->y_pixel + yscale / 2) + 
2678                 (mwindow->edl->session->show_titles ? 
2679                         mwindow->theme->title_bg_data->get_h() : 
2680                         0);
2681         zoom_sample = mwindow->edl->local_session->zoom_sample;
2683         zoom_units = track->to_doubleunits(zoom_sample / mwindow->edl->session->sample_rate);
2686 float TrackCanvas::percentage_to_value(float percentage, 
2687         int is_toggle,
2688         Auto *reference)
2690         float result;
2691         if(is_toggle)
2692         {
2693                 if(percentage > 0.5) 
2694                         result = 1;
2695                 else
2696                         result = 0;
2697         }
2698         else
2699         {
2700                 float automation_min = mwindow->edl->local_session->automation_min;
2701                 float automation_max = mwindow->edl->local_session->automation_max;
2702                 float automation_range = automation_max - automation_min;
2704                 result = percentage * automation_range + automation_min;
2705                 if(reference)
2706                 {
2707                         FloatAuto *ptr = (FloatAuto*)reference;
2708                         result -= ptr->value;
2709                 }
2710         }
2711         return result;
2715 void TrackCanvas::calculate_auto_position(double *x, 
2716         double *y,
2717         double *in_x,
2718         double *in_y,
2719         double *out_x,
2720         double *out_y,
2721         Auto *current,
2722         double unit_start,
2723         double zoom_units,
2724         double yscale)
2726         float automation_min = mwindow->edl->local_session->automation_min;
2727         float automation_max = mwindow->edl->local_session->automation_max;
2728         float automation_range = automation_max - automation_min;
2729         FloatAuto *ptr = (FloatAuto*)current;
2730         *x = (double)(ptr->position - unit_start) / zoom_units;
2731         *y = ((ptr->value - automation_min) /
2732                 automation_range - 0.5) * 
2733                 -yscale;
2734         if(in_x)
2735         {
2736                 *in_x = (double)(ptr->position + 
2737                         ptr->control_in_position - 
2738                         unit_start) /
2739                         zoom_units;
2740         }
2741         if(in_y)
2742         {
2743                 *in_y = (((ptr->value + ptr->control_in_value) -
2744                         automation_min) /
2745                         automation_range - 0.5) *
2746                         -yscale;
2747         }
2748         if(out_x)
2749         {
2750                 *out_x = (double)(ptr->position + 
2751                         ptr->control_out_position - 
2752                         unit_start) /
2753                         zoom_units;
2754         }
2755         if(out_y)
2756         {
2757                 *out_y = (((ptr->value + ptr->control_out_value) -
2758                         automation_min) /
2759                         automation_range - 0.5) *
2760                         -yscale;
2761         }
2768 int TrackCanvas::do_float_autos(Track *track, 
2769                 Autos *autos, 
2770                 int cursor_x, 
2771                 int cursor_y, 
2772                 int draw, 
2773                 int buttonpress,
2774                 int color,
2775                 Auto * &auto_instance)
2777         int result = 0;
2779         double view_start;
2780         double unit_start;
2781         double view_end;
2782         double unit_end;
2783         double yscale;
2784         int center_pixel;
2785         double zoom_sample;
2786         double zoom_units;
2787         double ax, ay, ax2, ay2;
2788         double in_x2, in_y2, out_x2, out_y2;
2789         int draw_auto;
2790         double slope;
2791         int skip = 0;
2792         
2793         auto_instance = 0;
2795         calculate_viewport(track, 
2796                 view_start,
2797                 unit_start,
2798                 view_end,
2799                 unit_end,
2800                 yscale,
2801                 center_pixel,
2802                 zoom_sample,
2803                 zoom_units);
2807 // Get first auto before start
2808         Auto *current = 0;
2809         Auto *previous = 0;
2810         for(current = autos->last; 
2811                 current && current->position >= unit_start; 
2812                 current = PREVIOUS)
2813                 ;
2815         if(current)
2816         {
2817                 calculate_auto_position(&ax, 
2818                         &ay,
2819                         0,
2820                         0,
2821                         0,
2822                         0,
2823                         current,
2824                         unit_start,
2825                         zoom_units,
2826                         yscale);
2827                 current = NEXT;
2828         }
2829         else
2830         {
2831                 current = autos->first ? autos->first : autos->default_auto;
2832                 if(current)
2833                 {
2834                         calculate_auto_position(&ax, 
2835                                 &ay,
2836                                 0,
2837                                 0,
2838                                 0,
2839                                 0,
2840                                 current,
2841                                 unit_start,
2842                                 zoom_units,
2843                                 yscale);
2844                         ax = 0;
2845                 }
2846                 else
2847                 {
2848                         ax = 0;
2849                         ay = 0;
2850                 }
2851         }
2857         do
2858         {
2859                 skip = 0;
2860                 draw_auto = 1;
2862                 if(current)
2863                 {
2864                         calculate_auto_position(&ax2, 
2865                                 &ay2,
2866                                 &in_x2,
2867                                 &in_y2,
2868                                 &out_x2,
2869                                 &out_y2,
2870                                 current,
2871                                 unit_start,
2872                                 zoom_units,
2873                                 yscale);
2874                 }
2875                 else
2876                 {
2877                         ax2 = get_w();
2878                         ay2 = ay;
2879                         skip = 1;
2880                 }
2882                 slope = (ay2 - ay) / (ax2 - ax);
2884                 if(ax2 > get_w())
2885                 {
2886                         draw_auto = 0;
2887                         ax2 = get_w();
2888                         ay2 = ay + slope * (get_w() - ax);
2889                 }
2890                 
2891                 if(ax < 0)
2892                 {
2893                         ay = ay + slope * (0 - ax);
2894                         ax = 0;
2895                 }
2910 // Draw handle
2911                 if(current && !result)
2912                 {
2913                         if(current != autos->default_auto)
2914                         {
2915                                 if(!draw)
2916                                 {
2917                                         if(track->record)
2918                                                 result = test_floatauto(current, 
2919                                                         (int)ax2, 
2920                                                         (int)ay2, 
2921                                                         (int)in_x2,
2922                                                         (int)in_y2,
2923                                                         (int)out_x2,
2924                                                         (int)out_y2,
2925                                                         (int)center_pixel, 
2926                                                         (int)yscale, 
2927                                                         cursor_x, 
2928                                                         cursor_y, 
2929                                                         buttonpress);
2930                                         if (result) 
2931                                                 auto_instance = current;
2932                                 }
2933                                 else
2934                                 if(draw_auto)
2935                                         draw_floatauto(current, 
2936                                                 (int)ax2, 
2937                                                 (int)ay2, 
2938                                                 (int)in_x2,
2939                                                 (int)in_y2,
2940                                                 (int)out_x2,
2941                                                 (int)out_y2,
2942                                                 (int)center_pixel, 
2943                                                 (int)yscale,
2944                                                 color);
2945                         }
2946                 }
2952 // Draw joining line
2953                 if(!draw)
2954                 {
2955                         if(!result)
2956                         {
2957                                 if(track->record && buttonpress != 3)
2958                                 {
2959                                         result = test_floatline(center_pixel, 
2960                                                 (FloatAutos*)autos,
2961                                                 unit_start,
2962                                                 zoom_units,
2963                                                 yscale,
2964                                                 (int)ax,
2965 // Exclude auto coverage from the end of the line.  The auto overlaps
2966                                                 (int)ax2 - HANDLE_W / 2,
2967                                                 cursor_x, 
2968                                                 cursor_y, 
2969                                                 buttonpress);
2970                                 }
2971                         }
2972                 }
2973                 else
2974                         draw_floatline(center_pixel,
2975                                 (FloatAuto*)previous,
2976                                 (FloatAuto*)current,
2977                                 (FloatAutos*)autos,
2978                                 unit_start,
2979                                 zoom_units,
2980                                 yscale,
2981                                 (int)ax, 
2982                                 (int)ay, 
2983                                 (int)ax2, 
2984                                 (int)ay2,
2985                                 color);
2993                 if(current)
2994                 {
2995                         previous = current;
2996                         current = NEXT;
2997                 }
3001                 ax = ax2;
3002                 ay = ay2;
3003         }while(current && 
3004                 current->position <= unit_end && 
3005                 !result);
3007 //printf("TrackCanvas::do_float_autos 100\n");
3016         if(ax < get_w() && !result)
3017         {
3018                 ax2 = get_w();
3019                 ay2 = ay;
3020                 if(!draw)
3021                 {
3022                         if(track->record && buttonpress != 3)
3023                         {
3024                                 result = test_floatline(center_pixel, 
3025                                         (FloatAutos*)autos,
3026                                         unit_start,
3027                                         zoom_units,
3028                                         yscale,
3029                                         (int)ax,
3030                                         (int)ax2,
3031                                         cursor_x, 
3032                                         cursor_y, 
3033                                         buttonpress);
3034                         }
3035                 }
3036                 else
3037                         draw_floatline(center_pixel, 
3038                                 (FloatAuto*)previous,
3039                                 (FloatAuto*)current,
3040                                 (FloatAutos*)autos,
3041                                 unit_start,
3042                                 zoom_units,
3043                                 yscale,
3044                                 (int)ax, 
3045                                 (int)ay, 
3046                                 (int)ax2, 
3047                                 (int)ay2,
3048                                 color);
3049         }
3058         return result;
3062 int TrackCanvas::do_toggle_autos(Track *track, 
3063                 Autos *autos, 
3064                 int cursor_x, 
3065                 int cursor_y, 
3066                 int draw, 
3067                 int buttonpress,
3068                 int color,
3069                 Auto * &auto_instance)
3071         int result = 0;
3072         double view_start;
3073         double unit_start;
3074         double view_end;
3075         double unit_end;
3076         double yscale;
3077         int center_pixel;
3078         double zoom_sample;
3079         double zoom_units;
3080         double ax, ay, ax2, ay2;
3081         
3082         auto_instance = 0;
3084         calculate_viewport(track, 
3085                 view_start,
3086                 unit_start,
3087                 view_end,
3088                 unit_end,
3089                 yscale,
3090                 center_pixel,
3091                 zoom_sample,
3092                 zoom_units);
3095         double high = -yscale * 0.8 / 2;
3096         double low = yscale * 0.8 / 2;
3098 // Get first auto before start
3099         Auto *current;
3100         for(current = autos->last; current && current->position >= unit_start; current = PREVIOUS)
3101                 ;
3103         if(current)
3104         {
3105                 ax = 0;
3106                 ay = ((IntAuto*)current)->value > 0 ? high : low;
3107                 current = NEXT;
3108         }
3109         else
3110         {
3111                 current = autos->first ? autos->first : autos->default_auto;
3112                 if(current)
3113                 {
3114                         ax = 0;
3115                         ay = ((IntAuto*)current)->value > 0 ? high : low;
3116                 }
3117                 else
3118                 {
3119                         ax = 0;
3120                         ay = yscale;
3121                 }
3122         }
3124         do
3125         {
3126                 if(current)
3127                 {
3128                         ax2 = (double)(current->position - unit_start) / zoom_units;
3129                         ay2 = ((IntAuto*)current)->value > 0 ? high : low;
3130                 }
3131                 else
3132                 {
3133                         ax2 = get_w();
3134                         ay2 = ay;
3135                 }
3137                 if(ax2 > get_w()) ax2 = get_w();
3139             if(current && !result) 
3140                 {
3141                         if(current != autos->default_auto)
3142                         {
3143                                 if(!draw)
3144                                 {
3145                                         if(track->record)
3146                                         {
3147                                                 result = test_auto(current, 
3148                                                         (int)ax2, 
3149                                                         (int)ay2, 
3150                                                         (int)center_pixel, 
3151                                                         (int)yscale, 
3152                                                         cursor_x, 
3153                                                         cursor_y, 
3154                                                         buttonpress);
3155                                                 if (result)
3156                                                         auto_instance = current;
3157                                         }
3158                                 }
3159                                 else
3160                                         draw_auto(current, 
3161                                                 (int)ax2, 
3162                                                 (int)ay2, 
3163                                                 (int)center_pixel, 
3164                                                 (int)yscale,
3165                                                 color);
3166                         }
3168                         current = NEXT;
3169                 }
3171                 if(!draw)
3172                 {
3173                         if(!result)
3174                         {
3175                                 if(track->record && buttonpress != 3)
3176                                 {
3177                                         result = test_toggleline(autos, 
3178                                                 center_pixel, 
3179                                                 (int)ax, 
3180                                                 (int)ay, 
3181                                                 (int)ax2, 
3182                                                 (int)ay2,
3183                                                 cursor_x, 
3184                                                 cursor_y, 
3185                                                 buttonpress);
3186                                 }
3187                         }
3188                 }
3189                 else
3190                         draw_toggleline(center_pixel, 
3191                                 (int)ax, 
3192                                 (int)ay, 
3193                                 (int)ax2, 
3194                                 (int)ay2,
3195                                 color);
3197                 ax = ax2;
3198                 ay = ay2;
3199         }while(current && current->position <= unit_end && !result);
3201         if(ax < get_w() && !result)
3202         {
3203                 ax2 = get_w();
3204                 ay2 = ay;
3205                 if(!draw)
3206                 {
3207                         if(track->record && buttonpress != 3)
3208                         {
3209                                 result = test_toggleline(autos,
3210                                         center_pixel, 
3211                                         (int)ax, 
3212                                         (int)ay, 
3213                                         (int)ax2, 
3214                                         (int)ay2,
3215                                         cursor_x, 
3216                                         cursor_y, 
3217                                         buttonpress);
3218                         }
3219                 }
3220                 else
3221                         draw_toggleline(center_pixel, 
3222                                 (int)ax, 
3223                                 (int)ay, 
3224                                 (int)ax2, 
3225                                 (int)ay2,
3226                                 color);
3227         }
3228         return result;
3231 int TrackCanvas::do_autos(Track *track, 
3232                 Autos *autos, 
3233                 int cursor_x, 
3234                 int cursor_y, 
3235                 int draw, 
3236                 int buttonpress,
3237                 BC_Pixmap *pixmap,
3238                 Auto * &auto_instance)
3240         int result = 0;
3242         double view_start;
3243         double unit_start;
3244         double view_end;
3245         double unit_end;
3246         double yscale;
3247         int center_pixel;
3248         double zoom_sample;
3249         double zoom_units;
3251         calculate_viewport(track, 
3252                 view_start,
3253                 unit_start,
3254                 view_end,
3255                 unit_end,
3256                 yscale,
3257                 center_pixel,
3258                 zoom_sample,
3259                 zoom_units);
3261         Auto *current;
3262         auto_instance = 0;
3264         for(current = autos->first; current && !result; current = NEXT)
3265         {
3266                 if(current->position >= unit_start && current->position < unit_end)
3267                 {
3268                         int64_t x, y;
3269                         x = (int64_t)((double)(current->position - unit_start) / 
3270                                 zoom_units - (pixmap->get_w() / 2 + 0.5));
3271                         y = center_pixel - pixmap->get_h() / 2;
3273                         if(!draw)
3274                         {
3275                                 if(cursor_x >= x && cursor_y >= y &&
3276                                         cursor_x < x + pixmap->get_w() &&
3277                                         cursor_y < y + pixmap->get_h())
3278                                 {
3279                                         result = 1;
3280                                         auto_instance = current;
3282                                         if(buttonpress && (buttonpress != 3))
3283                                         {
3284                                                 mwindow->session->drag_auto = current;
3285                                                 mwindow->session->drag_start_position = current->position;
3286                                                 mwindow->session->drag_origin_x = cursor_x;
3287                                                 mwindow->session->drag_origin_y = cursor_y;
3289                                                 double position = autos->track->from_units(current->position);
3290                                                 double center = (mwindow->edl->local_session->get_selectionstart(1) +
3291                                                         mwindow->edl->local_session->get_selectionend(1)) / 
3292                                                         2;
3294                                                 if(!shift_down())
3295                                                 {
3296                                                         mwindow->edl->local_session->set_selectionstart(position);
3297                                                         mwindow->edl->local_session->set_selectionend(position);
3298                                                 }
3299                                                 else
3300                                                 if(position < center)
3301                                                 {
3302                                                         mwindow->edl->local_session->set_selectionstart(position);
3303                                                 }
3304                                                 else
3305                                                         mwindow->edl->local_session->set_selectionend(position);
3306                                         }
3307                                 }
3308                         }
3309                         else
3310                                 draw_pixmap(pixmap, x, y);
3311                 }
3312         }
3313         return result;
3316 // so this means it is always >0 when keyframe is found 
3317 int TrackCanvas::do_plugin_autos(Track *track, 
3318                 int cursor_x, 
3319                 int cursor_y, 
3320                 int draw, 
3321                 int buttonpress,
3322                 Plugin* &keyframe_plugin,
3323                 KeyFrame* &keyframe_instance)
3325         int result = 0;
3327         double view_start;
3328         double unit_start;
3329         double view_end;
3330         double unit_end;
3331         double yscale;
3332         int center_pixel;
3333         double zoom_sample;
3334         double zoom_units;
3336         if(!track->expand_view) return 0;
3338         calculate_viewport(track, 
3339                 view_start,
3340                 unit_start,
3341                 view_end,
3342                 unit_end,
3343                 yscale,
3344                 center_pixel,
3345                 zoom_sample,
3346                 zoom_units);
3350         for(int i = 0; i < track->plugin_set.total && !result; i++)
3351         {
3352                 PluginSet *plugin_set = track->plugin_set.values[i];
3353                 int center_pixel = (int)(track->y_pixel + 
3354                         mwindow->edl->local_session->zoom_track +
3355                         (i + 0.5) * mwindow->theme->plugin_bg_data->get_h() + 
3356                         (mwindow->edl->session->show_titles ? mwindow->theme->title_bg_data->get_h() : 0));
3358                 for(Plugin *plugin = (Plugin*)plugin_set->first; 
3359                         plugin && !result; 
3360                         plugin = (Plugin*)plugin->next)
3361                 {
3362                         for(KeyFrame *keyframe = (KeyFrame*)plugin->keyframes->first; 
3363                                 keyframe && !result; 
3364                                 keyframe = (KeyFrame*)keyframe->next)
3365                         {
3366 //printf("TrackCanvas::draw_plugin_autos 3 %d\n", keyframe->position);
3367                                 if(keyframe->position >= unit_start && keyframe->position < unit_end)
3368                                 {
3369                                         int64_t x = (int64_t)((keyframe->position - unit_start) / zoom_units);
3370                                         int y = center_pixel - keyframe_pixmap->get_h() / 2;
3372 //printf("TrackCanvas::draw_plugin_autos 4 %d %d\n", x, center_pixel);
3373                                         if(!draw)
3374                                         {
3375                                                 if(cursor_x >= x && cursor_y >= y &&
3376                                                         cursor_x < x + keyframe_pixmap->get_w() &&
3377                                                         cursor_y < y + keyframe_pixmap->get_h())
3378                                                 {
3379                                                         result = 1;
3380                                                         keyframe_plugin = plugin;
3381                                                         keyframe_instance = keyframe;
3383                                                         if(buttonpress)
3384                                                         {
3385                                                                 mwindow->session->drag_auto = keyframe;
3386                                                                 mwindow->session->drag_start_position = keyframe->position;
3387                                                                 mwindow->session->drag_origin_x = cursor_x;
3388                                                                 mwindow->session->drag_origin_y = cursor_y;
3390                                                                 double position = track->from_units(keyframe->position);
3391                                                                 double center = (mwindow->edl->local_session->get_selectionstart(1) +
3392                                                                         mwindow->edl->local_session->get_selectionend(1)) / 
3393                                                                         2;
3395                                                                 if(!shift_down())
3396                                                                 {
3397                                                                         mwindow->edl->local_session->set_selectionstart(position);
3398                                                                         mwindow->edl->local_session->set_selectionend(position);
3399                                                                 }
3400                                                                 else
3401                                                                 if(position < center)
3402                                                                 {
3403                                                                         mwindow->edl->local_session->set_selectionstart(position);
3404                                                                 }
3405                                                                 else
3406                                                                         mwindow->edl->local_session->set_selectionend(position);
3407                                                         }
3408                                                 }
3409                                         }
3410                                         else
3411                                                 draw_pixmap(keyframe_pixmap, 
3412                                                         x, 
3413                                                         y);
3414                                 }
3415                         }
3416                 }
3417         }
3418 //printf("TrackCanvas::draw_plugin_autos 5\n");
3419         return result;
3422 void TrackCanvas::draw_overlays()
3424         int new_cursor, update_cursor, rerender;
3425 //TRACE("TrackCanvas::draw_overlays 1")
3427 // Move background pixmap to foreground pixmap
3428         draw_pixmap(background_pixmap, 
3429                 0, 
3430                 0,
3431                 get_w(),
3432                 get_h(),
3433                 0,
3434                 0);
3435 //TRACE("TrackCanvas::draw_overlays 10")
3437 // In/Out points
3438         draw_inout_points();
3440 //TRACE("TrackCanvas::draw_overlays 11");
3441 // Transitions
3442         if(mwindow->edl->session->auto_conf->transitions) draw_transitions();
3444 //TRACE("TrackCanvas::draw_overlays 12");
3445 // Plugins
3446         draw_plugins();
3448 //TRACE("TrackCanvas::draw_overlays 13");
3449 // Loop points
3450         draw_loop_points();
3451         draw_brender_start();
3453 //TRACE("TrackCanvas::draw_overlays 14");
3454 // Highlighted areas
3455         draw_highlighting();
3457 //TRACE("TrackCanvas::draw_overlays 15");
3458 // Automation
3459         do_keyframes(0, 
3460                 0, 
3461                 1, 
3462                 0, 
3463                 new_cursor, 
3464                 update_cursor,
3465                 rerender);
3467 //TRACE("TrackCanvas::draw_overlays 16\n");
3468 // Selection cursor
3469         if(gui->cursor) gui->cursor->restore();
3471 //TRACE("TrackCanvas::draw_overlays 17\n");
3472 // Handle dragging
3473         draw_drag_handle();
3475 //TRACE("TrackCanvas::draw_overlays 20");
3476 // Playback cursor
3477         draw_playback_cursor();
3481 int TrackCanvas::activate()
3483         if(!active)
3484         {
3485                 get_top_level()->deactivate();
3486                 active = 1;
3487                 set_active_subwindow(this);
3488                 gui->cursor->activate();
3489         }
3490         return 0;
3493 int TrackCanvas::deactivate()
3495         if(active)
3496         {
3497                 active = 0;
3498                 gui->cursor->deactivate();
3499         }
3500         return 0;
3504 void TrackCanvas::update_drag_handle()
3506         double new_position;
3508         new_position = 
3509                 (double)(get_cursor_x() + mwindow->edl->local_session->view_start) *
3510                 mwindow->edl->local_session->zoom_sample /
3511                 mwindow->edl->session->sample_rate;
3512         new_position = 
3513                 mwindow->edl->align_to_frame(new_position, 0);
3516         if(new_position != mwindow->session->drag_position)
3517         {
3518                 mwindow->session->drag_position = new_position;
3519                 gui->mainclock->update(new_position);
3520 // Que the CWindow.  Doesn't do anything if selectionstart and selection end 
3521 // aren't changed.
3522 //              mwindow->cwindow->update(1, 0, 0);
3523         }
3526 int TrackCanvas::update_drag_edit()
3528         int result = 0;
3529         
3530         
3531         
3532         return result;
3535 #define UPDATE_DRAG_HEAD(do_clamp) \
3536         int result = 0; \
3537         int x = cursor_x - mwindow->session->drag_origin_x; \
3538         int y = cursor_y - mwindow->session->drag_origin_y; \
3540         if(!current->autos->track->record) return 0; \
3541         double view_start; \
3542         double unit_start; \
3543         double view_end; \
3544         double unit_end; \
3545         double yscale; \
3546         int center_pixel; \
3547         double zoom_sample; \
3548         double zoom_units; \
3550         calculate_viewport(current->autos->track,  \
3551                 view_start, \
3552                 unit_start, \
3553                 view_end, \
3554                 unit_end, \
3555                 yscale, \
3556                 center_pixel, \
3557                 zoom_sample, \
3558                 zoom_units); \
3560         float percentage = (float)(mwindow->session->drag_origin_y - cursor_y) / \
3561                 yscale +  \
3562                 mwindow->session->drag_start_percentage; \
3563         if(do_clamp) CLAMP(percentage, 0, 1); \
3565         int64_t position = Units::to_int64(zoom_units * \
3566                 (cursor_x - mwindow->session->drag_origin_x) + \
3567                 mwindow->session->drag_start_position); \
3569         if((do_clamp) && position < 0) position = 0;
3579 int TrackCanvas::update_drag_floatauto(int cursor_x, int cursor_y)
3581         FloatAuto *current = (FloatAuto*)mwindow->session->drag_auto;
3583         UPDATE_DRAG_HEAD(mwindow->session->drag_handle == 0);
3585         float value;
3586         float old_value;
3588         switch(mwindow->session->drag_handle)
3589         {
3590 // Center
3591                 case 0:
3592 // Snap to nearby values
3593                         old_value = current->value;
3594                         if(shift_down())
3595                         {
3596                                 double value1;
3597                                 double distance1;
3598                                 double value2;
3599                                 double distance2;
3600                                 value = percentage_to_value(percentage, 0, 0);
3602                                 if(current->previous)
3603                                 {
3604                                         value1 = ((FloatAuto*)current->previous)->value;
3605                                         distance1 = fabs(value - value1);
3606                                         current->value = value1;
3607                                 }
3609                                 if(current->next)
3610                                 {
3611                                         value2 = ((FloatAuto*)current->next)->value;
3612                                         distance2 = fabs(value - value2);
3613                                         if(!current->previous || distance2 < distance1)
3614                                         {
3615                                                 current->value = value2;
3616                                         }
3617                                 }
3619                                 if(!current->previous && !current->next)
3620                                 {
3621                                         current->value = ((FloatAutos*)current->autos)->default_;
3622                                 }
3623                                 value = current->value;
3624                         }
3625                         else
3626                                 value = percentage_to_value(percentage, 0, 0);
3628                         if(value != old_value || position != current->position)
3629                         {
3630                                 result = 1;
3631                                 float change = value - old_value;               
3632                                 current->value = value;
3633                                 current->position = position;
3634                                 synchronize_autos(change, current->autos->track, current, 0);
3636                                 char string[BCTEXTLEN], string2[BCTEXTLEN];
3637                                 Units::totext(string2, 
3638                                         current->autos->track->from_units(current->position),
3639                                         mwindow->edl->session->time_format,
3640                                         mwindow->edl->session->sample_rate,
3641                                         mwindow->edl->session->frame_rate,
3642                                         mwindow->edl->session->frames_per_foot);
3643                                 sprintf(string, "%s, %.2f", string2, current->value);
3644                                 gui->show_message(string);
3645                         }
3646                         break;
3648 // In control
3649                 case 1:
3650                         value = percentage_to_value(percentage, 0, current);
3651                         position = MIN(0, position);
3652                         if(value != current->control_in_value || 
3653                                 position != current->control_in_position)
3654                         {
3655                                 result = 1;
3656                                 current->control_in_value = value;
3657                                 current->control_in_position = position;
3658                                 synchronize_autos(0, current->autos->track, current, 0);
3660                                 char string[BCTEXTLEN], string2[BCTEXTLEN];
3661                                 Units::totext(string2, 
3662                                         current->autos->track->from_units(current->control_in_position),
3663                                         mwindow->edl->session->time_format,
3664                                         mwindow->edl->session->sample_rate,
3665                                         mwindow->edl->session->frame_rate,
3666                                         mwindow->edl->session->frames_per_foot);
3667                                 sprintf(string, "%s, %.2f", string2, current->control_in_value);
3668                                 gui->show_message(string);
3669                         }
3670                         break;
3672 // Out control
3673                 case 2:
3674                         value = percentage_to_value(percentage, 0, current);
3675                         position = MAX(0, position);
3676                         if(value != current->control_out_value || 
3677                                 position != current->control_out_position)
3678                         {
3679                                 result = 1;
3680                                 current->control_out_value = value;
3681                                 current->control_out_position = position;
3682                                 synchronize_autos(0, current->autos->track, current, 0);
3684                                 char string[BCTEXTLEN], string2[BCTEXTLEN];
3685                                 Units::totext(string2, 
3686                                         current->autos->track->from_units(
3687                                                 ((FloatAuto*)current)->control_out_position),
3688                                         mwindow->edl->session->time_format,
3689                                         mwindow->edl->session->sample_rate,
3690                                         mwindow->edl->session->frame_rate,
3691                                         mwindow->edl->session->frames_per_foot);
3692                                 sprintf(string, "%s, %.2f", 
3693                                         string2, 
3694                                         ((FloatAuto*)current)->control_out_value);
3695                                 gui->show_message(string);
3696                         }
3697                         break;
3698         }
3700         return result;
3703 int TrackCanvas::update_drag_toggleauto(int cursor_x, int cursor_y)
3705         IntAuto *current = (IntAuto*)mwindow->session->drag_auto;
3707         UPDATE_DRAG_HEAD(1);
3709         int value = (int)percentage_to_value(percentage, 1, 0);
3711         if(value != current->value || position != current->position)
3712         {
3713                 result = 1;
3714                 current->value = value;
3715                 current->position = position;
3717                 char string[BCTEXTLEN], string2[BCTEXTLEN];
3718                 Units::totext(string2, 
3719                         current->autos->track->from_units(current->position),
3720                         mwindow->edl->session->time_format,
3721                         mwindow->edl->session->sample_rate,
3722                         mwindow->edl->session->frame_rate,
3723                         mwindow->edl->session->frames_per_foot);
3724                 sprintf(string, "%s, %d", string2, current->value);
3725                 gui->show_message(string);
3726         }
3728         return result;
3731 // Autos which can't change value through dragging.
3733 int TrackCanvas::update_drag_auto(int cursor_x, int cursor_y)
3735         Auto *current = (Auto*)mwindow->session->drag_auto;
3737         UPDATE_DRAG_HEAD(1)
3738         if(position != current->position)
3739         {
3740                 result = 1;
3741                 current->position = position;
3743                 char string[BCTEXTLEN];
3744                 Units::totext(string, 
3745                         current->autos->track->from_units(current->position),
3746                         mwindow->edl->session->time_format,
3747                         mwindow->edl->session->sample_rate,
3748                         mwindow->edl->session->frame_rate,
3749                         mwindow->edl->session->frames_per_foot);
3750                 gui->show_message(string);
3752                 double position_f = current->autos->track->from_units(current->position);
3753                 double center_f = (mwindow->edl->local_session->get_selectionstart(1) +
3754                         mwindow->edl->local_session->get_selectionend(1)) / 
3755                         2;
3756                 if(!shift_down())
3757                 {
3758                         mwindow->edl->local_session->set_selectionstart(position_f);
3759                         mwindow->edl->local_session->set_selectionend(position_f);
3760                 }
3761                 else
3762                 if(position_f < center_f)
3763                 {
3764                         mwindow->edl->local_session->set_selectionstart(position_f);
3765                 }
3766                 else
3767                         mwindow->edl->local_session->set_selectionend(position_f);
3768         }
3771         return result;
3774 int TrackCanvas::update_drag_pluginauto(int cursor_x, int cursor_y)
3776         KeyFrame *current = (KeyFrame*)mwindow->session->drag_auto;
3778         UPDATE_DRAG_HEAD(1)
3779         if(position != current->position)
3780         {
3781 //      printf("uida: autos: %p, track: %p ta: %p\n", current->autos, current->autos->track, current->autos->track->automation);
3782                 Track *track = current->autos->track;
3783                 PluginAutos *pluginautos = (PluginAutos *)current->autos;
3784                 PluginSet *pluginset;
3785                 Plugin *plugin;
3786                 // figure out the correct pluginset & correct plugin 
3787                 int found = 0;
3788                 for(int i = 0; i < track->plugin_set.total; i++)
3789                 {
3790                         pluginset = track->plugin_set.values[i];
3791                         for(plugin = (Plugin *)pluginset->first; plugin; plugin = (Plugin *)plugin->next)
3792                         {
3793                                 KeyFrames *keyframes = plugin->keyframes;
3794                                 for(KeyFrame *currentkeyframe = (KeyFrame *)keyframes->first; currentkeyframe; currentkeyframe = (KeyFrame *) currentkeyframe->next)
3795                                 {
3796                                         if (currentkeyframe == current) 
3797                                         {
3798                                                 found = 1;
3799                                                 break;
3800                                         }
3802                                 }
3803                                 if (found) break;                       
3804                         }
3805                         if (found) break;                       
3806                 }       
3807         
3808                 mwindow->session->plugin_highlighted = plugin;
3809                 mwindow->session->track_highlighted = track;
3810                 result = 1;
3811                 current->position = position;
3813                 char string[BCTEXTLEN];
3814                 Units::totext(string, 
3815                         current->autos->track->from_units(current->position),
3816                         mwindow->edl->session->time_format,
3817                         mwindow->edl->session->sample_rate,
3818                         mwindow->edl->session->frame_rate,
3819                         mwindow->edl->session->frames_per_foot);
3820                 gui->show_message(string);
3822                 double position_f = current->autos->track->from_units(current->position);
3823                 double center_f = (mwindow->edl->local_session->get_selectionstart(1) +
3824                         mwindow->edl->local_session->get_selectionend(1)) / 
3825                         2;
3826                 if(!shift_down())
3827                 {
3828                         mwindow->edl->local_session->set_selectionstart(position_f);
3829                         mwindow->edl->local_session->set_selectionend(position_f);
3830                 }
3831                 else
3832                 if(position_f < center_f)
3833                 {
3834                         mwindow->edl->local_session->set_selectionstart(position_f);
3835                 }
3836                 else
3837                         mwindow->edl->local_session->set_selectionend(position_f);
3838         }
3841         return result;
3844 void TrackCanvas::update_drag_caption()
3846         switch(mwindow->session->current_operation)
3847         {
3848                 case DRAG_FADE:
3849                         
3850                         break;
3851         }
3856 int TrackCanvas::cursor_motion_event()
3858         int result, cursor_x, cursor_y;
3859         int update_clock = 0;
3860         int update_zoom = 0;
3861         int update_scroll = 0;
3862         int update_overlay = 0;
3863         int update_cursor = 0;
3864         int new_cursor = 0;
3865         int rerender = 0;
3866         double position = 0;
3867 //printf("TrackCanvas::cursor_motion_event 1\n");
3868         result = 0;
3870 // Default cursor
3871         switch(mwindow->edl->session->editing_mode)
3872         {
3873                 case EDITING_ARROW: new_cursor = ARROW_CURSOR; break;
3874                 case EDITING_IBEAM: new_cursor = IBEAM_CURSOR; break;
3875         }
3877         switch(mwindow->session->current_operation)
3878         {
3879                 case DRAG_EDITHANDLE1:
3880 // Outside threshold.  Upgrade status
3881                         if(labs(get_cursor_x() - mwindow->session->drag_origin_x) > HANDLE_W)
3882                         {
3883                                 mwindow->session->current_operation = DRAG_EDITHANDLE2;
3884                                 update_overlay = 1;
3885                         }
3886                         break;
3888                 case DRAG_EDITHANDLE2:
3889                         update_drag_handle();
3890                         update_overlay = 1;
3891                         break;
3893                 case DRAG_PLUGINHANDLE1:
3894                         if(labs(get_cursor_x() - mwindow->session->drag_origin_x) > HANDLE_W)
3895                         {
3896                                 mwindow->session->current_operation = DRAG_PLUGINHANDLE2;
3897                                 update_overlay = 1;
3898                         }
3899                         break;
3901                 case DRAG_PLUGINHANDLE2:
3902                         update_drag_handle();
3903                         update_overlay = 1;
3904                         break;
3906 // Rubber band curves
3907                 case DRAG_FADE:
3908                 case DRAG_CZOOM:
3909                 case DRAG_PZOOM:
3910                 case DRAG_CAMERA_X:
3911                 case DRAG_CAMERA_Y:
3912                 case DRAG_CAMERA_Z:
3913                 case DRAG_PROJECTOR_X:
3914                 case DRAG_PROJECTOR_Y:
3915                 case DRAG_PROJECTOR_Z:
3916                         rerender = update_overlay = update_drag_floatauto(get_cursor_x(), get_cursor_y());
3917                         break;
3919                 case DRAG_PLAY:
3920                         rerender = update_overlay = update_drag_toggleauto(get_cursor_x(), get_cursor_y());
3921                         break;
3923                 case DRAG_MUTE:
3924                         rerender = update_overlay = update_drag_toggleauto(get_cursor_x(), get_cursor_y());
3925                         break;
3927 // Keyframe icons are sticky
3928                 case DRAG_PAN_PRE:
3929                 case DRAG_MASK_PRE:
3930                 case DRAG_MODE_PRE:
3931                 case DRAG_PLUGINKEY_PRE:
3932                         if(labs(get_cursor_x() - mwindow->session->drag_origin_x) > HANDLE_W)
3933                         {
3934                                 mwindow->session->current_operation++;
3935                                 update_overlay = 1;
3936                         }
3937                         break;
3939                 case DRAG_PAN:
3940                 case DRAG_MASK:
3941                 case DRAG_MODE:
3942                 case DRAG_PLUGINKEY:
3943                         rerender = update_overlay = 
3944                                 update_drag_pluginauto(get_cursor_x(), get_cursor_y());
3945                         break;
3947                 case SELECT_REGION:
3948                 {
3949                         cursor_x = get_cursor_x();
3950                         cursor_y = get_cursor_y();
3951                         position = (double)(cursor_x + mwindow->edl->local_session->view_start) * 
3952                                 mwindow->edl->local_session->zoom_sample /
3953                                 mwindow->edl->session->sample_rate;
3955                         position = mwindow->edl->align_to_frame(position, 0);
3956                         position = MAX(position, 0);
3958                         if(position < selection_midpoint1)
3959                         {
3960                                 mwindow->edl->local_session->set_selectionend(selection_midpoint1);
3961                                 mwindow->edl->local_session->set_selectionstart(position);
3962 // Que the CWindow
3963                                 gui->unlock_window();
3964                                 mwindow->cwindow->update(1, 0, 0, 0, 1);
3965                                 gui->lock_window("TrackCanvas::cursor_motion_event 1");
3966 // Update the faders
3967                                 mwindow->update_plugin_guis();
3968                                 gui->patchbay->update();
3969                         }
3970                         else
3971                         {
3972                                 mwindow->edl->local_session->set_selectionstart(selection_midpoint1);
3973                                 mwindow->edl->local_session->set_selectionend(position);
3974 // Don't que the CWindow
3975                         }
3977                         gui->cursor->hide();
3978                         gui->cursor->draw();
3979                         flash();
3980                         result = 1;
3981                         update_clock = 1;
3982                         update_zoom = 1;
3983                         update_scroll = 1;
3984                         break;
3985                 }
3987                 default:
3988                         if(is_event_win() && cursor_inside())
3989                         {
3990 // Update clocks
3991                                 cursor_x = get_cursor_x();
3992                                 position = (double)cursor_x * 
3993                                         (double)mwindow->edl->local_session->zoom_sample / 
3994                                         (double)mwindow->edl->session->sample_rate + 
3995                                         (double)mwindow->edl->local_session->view_start * 
3996                                         (double)mwindow->edl->local_session->zoom_sample / 
3997                                         (double)mwindow->edl->session->sample_rate;
3998                                 position = mwindow->edl->align_to_frame(position, 0);
3999                                 update_clock = 1;
4001 // Update cursor
4002                                 if(do_transitions(get_cursor_x(), 
4003                                                 get_cursor_y(), 
4004                                                 0, 
4005                                                 new_cursor, 
4006                                                 update_cursor))
4007                                 {
4008                                         break;
4009                                 }
4010                                 else
4011 // Update cursor
4012                                 if(do_keyframes(get_cursor_x(), 
4013                                         get_cursor_y(), 
4014                                         0, 
4015                                         0, 
4016                                         new_cursor,
4017                                         update_cursor,
4018                                         rerender))
4019                                 {
4020                                         break;
4021                                 }
4022                                 else
4023 // Edit boundaries
4024                                 if(do_edit_handles(get_cursor_x(), 
4025                                         get_cursor_y(), 
4026                                         0, 
4027                                         new_cursor,
4028                                         update_cursor))
4029                                 {
4030                                         break;
4031                                 }
4032                                 else
4033 // Plugin boundaries
4034                                 if(do_plugin_handles(get_cursor_x(), 
4035                                         get_cursor_y(), 
4036                                         0, 
4037                                         new_cursor,
4038                                         update_cursor))
4039                                 {
4040                                         break;
4041                                 }
4042                                 else
4043                                 if(do_edits(get_cursor_x(), 
4044                                         get_cursor_y(), 
4045                                         0, 
4046                                         0, 
4047                                         update_overlay, 
4048                                         rerender,
4049                                         new_cursor,
4050                                         update_cursor))
4051                                 {
4052                                         break;
4053                                 }
4054                         }
4055                         break;
4056         }
4058 //printf("TrackCanvas::cursor_motion_event 1\n");
4059         if(update_cursor && new_cursor != get_cursor())
4060         {
4061                 set_cursor(new_cursor);
4062         }
4064 //printf("TrackCanvas::cursor_motion_event 1 %d\n", rerender);
4065         if(rerender)
4066         {
4067                 mwindow->restart_brender();
4068                 mwindow->sync_parameters(CHANGE_PARAMS);
4069                 mwindow->update_plugin_guis();
4070                 gui->unlock_window();
4071                 mwindow->cwindow->update(1, 0, 0, 0, 1);
4072                 gui->lock_window("TrackCanvas::cursor_motion_event 2");
4073 // Update faders
4074                 gui->patchbay->update();
4075         }
4078         if(update_clock)
4079         {
4080                 if(!mwindow->cwindow->playback_engine->is_playing_back)
4081                         gui->mainclock->update(position);
4082         }
4084         if(update_zoom)
4085         {
4086                 gui->zoombar->update();
4087         }
4089         if(update_scroll)
4090         {
4091                 if(!drag_scroll && 
4092                         (cursor_x >= get_w() || cursor_x < 0 || cursor_y >= get_h() || cursor_y < 0))
4093                         start_dragscroll();
4094                 else
4095                 if(drag_scroll &&
4096                         (cursor_x < get_w() && cursor_x >= 0 && cursor_y < get_h() && cursor_y >= 0))
4097                         stop_dragscroll();
4098         }
4100         if(update_overlay)
4101         {
4102                 draw_overlays();
4103                 flash();
4104         }
4107 //printf("TrackCanvas::cursor_motion_event 100\n");
4108         return result;
4111 void TrackCanvas::start_dragscroll()
4113         if(!drag_scroll)
4114         {
4115                 drag_scroll = 1;
4116                 set_repeat(BC_WindowBase::get_resources()->scroll_repeat);
4117 //printf("TrackCanvas::start_dragscroll 1\n");
4118         }
4121 void TrackCanvas::stop_dragscroll()
4123         if(drag_scroll)
4124         {
4125                 drag_scroll = 0;
4126                 unset_repeat(BC_WindowBase::get_resources()->scroll_repeat);
4127 //printf("TrackCanvas::stop_dragscroll 1\n");
4128         }
4131 int TrackCanvas::repeat_event(int64_t duration)
4133         if(!drag_scroll) return 0;
4134         if(duration != BC_WindowBase::get_resources()->scroll_repeat) return 0;
4136         int sample_movement = 0;
4137         int track_movement = 0;
4138         int64_t x_distance = 0;
4139         int64_t y_distance = 0;
4140         double position = 0;
4141         int result = 0;
4143         switch(mwindow->session->current_operation)
4144         {
4145                 case SELECT_REGION:
4146 //printf("TrackCanvas::repeat_event 1 %d\n", mwindow->edl->local_session->view_start);
4147                         if(get_cursor_x() > get_w())
4148                         {
4149                                 x_distance = get_cursor_x() - get_w();
4150                                 sample_movement = 1;
4151                         }
4152                         else
4153                         if(get_cursor_x() < 0)
4154                         {
4155                                 x_distance = get_cursor_x();
4156                                 sample_movement = 1;
4157                         }
4159                         if(get_cursor_y() > get_h())
4160                         {
4161                                 y_distance = get_cursor_y() - get_h();
4162                                 track_movement = 1;
4163                         }
4164                         else
4165                         if(get_cursor_y() < 0)
4166                         {
4167                                 y_distance = get_cursor_y();
4168                                 track_movement = 1;
4169                         }
4170                         result = 1;
4171                         break;
4172         }
4175         if(sample_movement)
4176         {
4177                 position = (double)(get_cursor_x() + 
4178                         mwindow->edl->local_session->view_start + 
4179                         x_distance) * 
4180                         mwindow->edl->local_session->zoom_sample /
4181                         mwindow->edl->session->sample_rate;
4182                 position = mwindow->edl->align_to_frame(position, 0);
4183                 position = MAX(position, 0);
4185 //printf("TrackCanvas::repeat_event 1 %f\n", position);
4186                 switch(mwindow->session->current_operation)
4187                 {
4188                         case SELECT_REGION:
4189                                 if(position < selection_midpoint1)
4190                                 {
4191                                         mwindow->edl->local_session->set_selectionend(selection_midpoint1);
4192                                         mwindow->edl->local_session->set_selectionstart(position);
4193 // Que the CWindow
4194                                         gui->unlock_window();
4195                                         mwindow->cwindow->update(1, 0, 0);
4196                                         gui->lock_window("TrackCanvas::repeat_event");
4197 // Update the faders
4198                                         mwindow->update_plugin_guis();
4199                                         gui->patchbay->update();
4200                                 }
4201                                 else
4202                                 {
4203                                         mwindow->edl->local_session->set_selectionstart(selection_midpoint1);
4204                                         mwindow->edl->local_session->set_selectionend(position);
4205 // Don't que the CWindow
4206                                 }
4207                                 break;
4208                 }
4210                 mwindow->samplemovement(mwindow->edl->local_session->view_start + 
4211                         x_distance);
4212         }
4214         if(track_movement)
4215         {
4216                 mwindow->trackmovement(mwindow->edl->local_session->track_start + 
4217                         y_distance);
4218         }
4220         return result;
4223 int TrackCanvas::button_release_event()
4225         int redraw = 0, update_overlay = 0, result = 0;
4227         switch(mwindow->session->current_operation)
4228         {
4229                 case DRAG_EDITHANDLE2:
4230                         mwindow->session->current_operation = NO_OPERATION;
4231                         drag_scroll = 0;
4232                         result = 1;
4233                         
4234                         end_edithandle_selection();
4235                         break;
4237                 case DRAG_EDITHANDLE1:
4238                         mwindow->session->current_operation = NO_OPERATION;
4239                         drag_scroll = 0;
4240                         result = 1;
4241                         break;
4243                 case DRAG_PLUGINHANDLE2:
4244                         mwindow->session->current_operation = NO_OPERATION;
4245                         drag_scroll = 0;
4246                         result = 1;
4247                         
4248                         end_pluginhandle_selection();
4249                         break;
4251                 case DRAG_PLUGINHANDLE1:
4252                         mwindow->session->current_operation = NO_OPERATION;
4253                         drag_scroll = 0;
4254                         result = 1;
4255                         break;
4257                 case DRAG_FADE:
4258 // delete the drag_auto_gang first and remove out of order keys
4259                         synchronize_autos(0, 0, 0, -1); 
4260                 case DRAG_CZOOM:
4261                 case DRAG_PZOOM:
4262                 case DRAG_PLAY:
4263                 case DRAG_MUTE:
4264                 case DRAG_MASK:
4265                 case DRAG_MODE:
4266                 case DRAG_PAN:
4267                 case DRAG_CAMERA_X:
4268                 case DRAG_CAMERA_Y:
4269                 case DRAG_CAMERA_Z:
4270                 case DRAG_PROJECTOR_X:
4271                 case DRAG_PROJECTOR_Y:
4272                 case DRAG_PROJECTOR_Z:
4273                 case DRAG_PLUGINKEY:
4274                         mwindow->session->current_operation = NO_OPERATION;
4275                         mwindow->session->drag_handle = 0;
4276 // Remove any out-of-order keyframe
4277                         if(mwindow->session->drag_auto)
4278                         {
4279                                 mwindow->session->drag_auto->autos->remove_nonsequential(
4280                                         mwindow->session->drag_auto);
4281 //                              mwindow->session->drag_auto->autos->optimize();
4282                                 update_overlay = 1;
4283                         }
4284                         mwindow->undo->update_undo(_("keyframe"), LOAD_AUTOMATION);
4285                         result = 1;
4286                         break;
4288                 case DRAG_EDIT:
4289                 case DRAG_AEFFECT_COPY:
4290                 case DRAG_VEFFECT_COPY:
4291 // Trap in drag stop
4293                         break;
4296                 default:
4297                         if(mwindow->session->current_operation)
4298                         {
4299                                 if(mwindow->session->current_operation == SELECT_REGION)
4300                                 {
4301                                         mwindow->undo->update_undo(_("select"), LOAD_SESSION, 0, 0);
4302                                 }
4304                                 mwindow->session->current_operation = NO_OPERATION;
4305                                 drag_scroll = 0;
4306 // Traps button release events
4307 //                              result = 1;
4308                         }
4309                         break;
4310         }
4311         if (result) 
4312                 cursor_motion_event();
4313         if(update_overlay)
4314         {
4315                 draw_overlays();
4316                 flash();
4317                 flush();
4318         }
4319         if(redraw)
4320         {
4321                 draw();
4322                 flash();
4323                 flush();
4324         }
4325         return result;
4328 int TrackCanvas::do_edit_handles(int cursor_x, 
4329         int cursor_y, 
4330         int button_press, 
4331         int &new_cursor,
4332         int &update_cursor)
4334         Edit *edit_result = 0;
4335         int handle_result = 0;
4336         int result = 0;
4338         if(!mwindow->edl->session->show_assets) return 0;
4340         for(Track *track = mwindow->edl->tracks->first;
4341                 track && !result;
4342                 track = track->next)
4343         {
4344                 for(Edit *edit = track->edits->first;
4345                         edit && !result;
4346                         edit = edit->next)
4347                 {
4348                         int64_t edit_x, edit_y, edit_w, edit_h;
4349                         edit_dimensions(edit, edit_x, edit_y, edit_w, edit_h);
4351                         if(cursor_x >= edit_x && cursor_x <= edit_x + edit_w &&
4352                                 cursor_y >= edit_y && cursor_y < edit_y + edit_h)
4353                         {
4354                                 if(cursor_x < edit_x + HANDLE_W)
4355                                 {
4356                                         edit_result = edit;
4357                                         handle_result = 0;
4358                                         result = 1;
4359                                 }
4360                                 else
4361                                 if(cursor_x >= edit_x + edit_w - HANDLE_W)
4362                                 {
4363                                         edit_result = edit;
4364                                         handle_result = 1;
4365                                         result = 1;
4366                                 }
4367                                 else
4368                                 {
4369                                         result = 0;
4370                                 }
4371                         }
4372                 }
4373         }
4375         update_cursor = 1;
4376         if(result)
4377         {
4378                 double position;
4379                 if(handle_result == 0)
4380                 {
4381                         position = edit_result->track->from_units(edit_result->startproject);
4382                         new_cursor = LEFT_CURSOR;
4383                 }
4384                 else
4385                 if(handle_result == 1)
4386                 {
4387                         position = edit_result->track->from_units(edit_result->startproject + edit_result->length);
4388                         new_cursor = RIGHT_CURSOR;
4389                 };
4391 // Reposition cursor
4392                 if(button_press)
4393                 {
4394                         mwindow->session->drag_edit = edit_result;
4395                         mwindow->session->drag_handle = handle_result;
4396                         mwindow->session->drag_button = get_buttonpress() - 1;
4397                         mwindow->session->drag_position = position;
4398                         mwindow->session->current_operation = DRAG_EDITHANDLE1;
4399                         mwindow->session->drag_origin_x = get_cursor_x();
4400                         mwindow->session->drag_origin_y = get_cursor_y();
4401                         mwindow->session->drag_start = position;
4403                         int rerender = start_selection(position);
4404                         if(rerender)
4405                         {
4406                                 gui->unlock_window();
4407                                 mwindow->cwindow->update(1, 0, 0);
4408                                 gui->lock_window("TrackCanvas::do_edit_handles");
4409                         }
4410                         gui->timebar->update_highlights();
4411                         gui->zoombar->update();
4412                         gui->cursor->hide();
4413                         gui->cursor->draw();
4414                         draw_overlays();
4415                         flash();
4416                         flush();
4417                 }
4418         }
4420         return result;
4423 int TrackCanvas::do_plugin_handles(int cursor_x, 
4424         int cursor_y, 
4425         int button_press,
4426         int &new_cursor,
4427         int &update_cursor)
4429         Plugin *plugin_result = 0;
4430         int handle_result = 0;
4431         int result = 0;
4433         if(!mwindow->edl->session->show_assets) return 0;
4435         for(Track *track = mwindow->edl->tracks->first;
4436                 track && !result;
4437                 track = track->next)
4438         {
4439                 for(int i = 0; i < track->plugin_set.total && !result; i++)
4440                 {
4441                         PluginSet *plugin_set = track->plugin_set.values[i];
4442                         for(Plugin *plugin = (Plugin*)plugin_set->first; 
4443                                 plugin && !result; 
4444                                 plugin = (Plugin*)plugin->next)
4445                         {
4446                                 int64_t plugin_x, plugin_y, plugin_w, plugin_h;
4447                                 plugin_dimensions(plugin, plugin_x, plugin_y, plugin_w, plugin_h);
4449                                 if(cursor_x >= plugin_x && cursor_x <= plugin_x + plugin_w &&
4450                                         cursor_y >= plugin_y && cursor_y < plugin_y + plugin_h)
4451                                 {
4452                                         if(cursor_x < plugin_x + HANDLE_W)
4453                                         {
4454                                                 plugin_result = plugin;
4455                                                 handle_result = 0;
4456                                                 result = 1;
4457                                         }
4458                                         else
4459                                         if(cursor_x >= plugin_x + plugin_w - HANDLE_W)
4460                                         {
4461                                                 plugin_result = plugin;
4462                                                 handle_result = 1;
4463                                                 result = 1;
4464                                         }
4465                                 }
4466                         }
4468                         if(result && shift_down())
4469                                 mwindow->session->trim_edits = plugin_set;
4470                 }
4471         }
4473         update_cursor = 1;
4474         if(result)
4475         {
4476                 double position;
4477                 if(handle_result == 0)
4478                 {
4479                         position = plugin_result->track->from_units(plugin_result->startproject);
4480                         new_cursor = LEFT_CURSOR;
4481                 }
4482                 else
4483                 if(handle_result == 1)
4484                 {
4485                         position = plugin_result->track->from_units(plugin_result->startproject + plugin_result->length);
4486                         new_cursor = RIGHT_CURSOR;
4487                 }
4488                 
4489                 if(button_press)
4490                 {
4491                         mwindow->session->drag_plugin = plugin_result;
4492                         mwindow->session->drag_handle = handle_result;
4493                         mwindow->session->drag_button = get_buttonpress() - 1;
4494                         mwindow->session->drag_position = position;
4495                         mwindow->session->current_operation = DRAG_PLUGINHANDLE1;
4496                         mwindow->session->drag_origin_x = get_cursor_x();
4497                         mwindow->session->drag_origin_y = get_cursor_y();
4498                         mwindow->session->drag_start = position;
4500                         int rerender = start_selection(position);
4501                         if(rerender) 
4502                         {
4503                                 gui->unlock_window();
4504                                 mwindow->cwindow->update(1, 0, 0);
4505                                 gui->lock_window("TrackCanvas::do_plugin_handles");
4506                         }
4507                         gui->timebar->update_highlights();
4508                         gui->zoombar->update();
4509                         gui->cursor->hide();
4510                         gui->cursor->draw();
4511                         draw_overlays();
4512                         flash();
4513                         flush();
4514                 }
4515         }
4516         
4517         return result;
4521 int TrackCanvas::do_tracks(int cursor_x, 
4522                 int cursor_y,
4523                 int button_press)
4525         int result = 0;
4528         if(!mwindow->edl->session->show_assets) return 0;
4531         for(Track *track = mwindow->edl->tracks->first;
4532                 track && !result;
4533                 track = track->next)
4534         {
4535                 int64_t track_x, track_y, track_w, track_h;
4536                 track_dimensions(track, track_x, track_y, track_w, track_h);
4538                 if(button_press && 
4539                         get_buttonpress() == 3 &&
4540                         cursor_y >= track_y && 
4541                         cursor_y < track_y + track_h)
4542                 {
4543                         gui->edit_menu->update(track, 0);
4544                         gui->edit_menu->activate_menu();
4545                         result = 1;
4546                 }
4547         }
4548         return result;
4551 int TrackCanvas::do_edits(int cursor_x, 
4552         int cursor_y, 
4553         int button_press,
4554         int drag_start,
4555         int &redraw,
4556         int &rerender,
4557         int &new_cursor,
4558         int &update_cursor)
4560         int result = 0;
4561         int over_edit_handle = 0;
4563         if(!mwindow->edl->session->show_assets) return 0;
4565         for(Track *track = mwindow->edl->tracks->first;
4566                 track && !result;
4567                 track = track->next)
4568         {
4569                 for(Edit *edit = track->edits->first;
4570                         edit && !result;
4571                         edit = edit->next)
4572                 {
4573                         int64_t edit_x, edit_y, edit_w, edit_h;
4574                         edit_dimensions(edit, edit_x, edit_y, edit_w, edit_h);
4576 // Cursor inside a track
4577 // Cursor inside an edit
4578                         if(cursor_x >= edit_x && cursor_x < edit_x + edit_w &&
4579                                 cursor_y >= edit_y && cursor_y < edit_y + edit_h)
4580                         {
4581 // Select duration of edit
4582                                 if(button_press)
4583                                 {
4584                                         if(get_double_click() && !drag_start)
4585                                         {
4586                                                 mwindow->edl->local_session->set_selectionstart(edit->track->from_units(edit->startproject));
4587                                                 mwindow->edl->local_session->set_selectionend(edit->track->from_units(edit->startproject) + 
4588                                                         edit->track->from_units(edit->length));
4589                                                 if(mwindow->edl->session->cursor_on_frames) 
4590                                                 {
4591                                                         mwindow->edl->local_session->set_selectionstart(
4592                                                                 mwindow->edl->align_to_frame(mwindow->edl->local_session->get_selectionstart(1), 0));
4593                                                         mwindow->edl->local_session->set_selectionend(
4594                                                                 mwindow->edl->align_to_frame(mwindow->edl->local_session->get_selectionend(1), 1));
4595                                                 }
4596                                                 redraw = 1;
4597                                                 rerender = 1;
4598                                                 result = 1;
4599                                         }
4600                                 }
4601                                 else
4602                                 if(drag_start && track->record)
4603                                 {
4604                                         if(mwindow->edl->session->editing_mode == EDITING_ARROW)
4605                                         {
4606 // Need to create drag window
4607                                                 mwindow->session->current_operation = DRAG_EDIT;
4608                                                 mwindow->session->drag_edit = edit;
4609 //printf("TrackCanvas::do_edits 2\n");
4611 // Drag only one edit
4612                                                 if(ctrl_down())
4613                                                 {
4614                                                         mwindow->session->drag_edits->remove_all();
4615                                                         mwindow->session->drag_edits->append(edit);
4616                                                 }
4617                                                 else
4618 // Construct list of all affected edits
4619                                                 {
4620                                                         mwindow->edl->tracks->get_affected_edits(
4621                                                                 mwindow->session->drag_edits, 
4622                                                                 edit->track->from_units(edit->startproject),
4623                                                                 edit->track);
4624                                                 }
4625                                                 mwindow->session->drag_origin_x = cursor_x;
4626                                                 mwindow->session->drag_origin_y = cursor_y;
4627                                                 // Where the drag started, so we know relative position inside the edit later
4628                                                 mwindow->session->drag_position = (double)cursor_x * 
4629                                                         mwindow->edl->local_session->zoom_sample / 
4630                                                         mwindow->edl->session->sample_rate + 
4631                                                         (double)mwindow->edl->local_session->view_start * 
4632                                                         mwindow->edl->local_session->zoom_sample /
4633                                                         mwindow->edl->session->sample_rate;
4634                                                 
4635                                                 drag_popup = new BC_DragWindow(gui, 
4636                                                         mwindow->theme->get_image("clip_icon"), 
4637                                                         get_abs_cursor_x(0) - mwindow->theme->get_image("clip_icon")->get_w() / 2,
4638                                                         get_abs_cursor_y(0) - mwindow->theme->get_image("clip_icon")->get_h() / 2);
4640                                                 result = 1;
4641                                         }
4642                                 }
4643                         }
4644                 }
4645         }
4646         return result;
4650 int TrackCanvas::test_resources(int cursor_x, int cursor_y)
4652         return 0;
4655 int TrackCanvas::do_plugins(int cursor_x, 
4656         int cursor_y, 
4657         int drag_start,
4658         int button_press,
4659         int &redraw,
4660         int &rerender)
4662         Plugin *plugin = 0;
4663         int result = 0;
4664         int done = 0;
4665         int64_t x, y, w, h;
4666         Track *track = 0;
4669         if(!mwindow->edl->session->show_assets) return 0;
4672         for(track = mwindow->edl->tracks->first;
4673                 track && !done;
4674                 track = track->next)
4675         {
4676                 if(!track->expand_view) continue;
4679                 for(int i = 0; i < track->plugin_set.total && !done; i++)
4680                 {
4681                         // first check if plugins are visible at all
4682                         if (!track->expand_view)
4683                                 continue;
4684                         PluginSet *plugin_set = track->plugin_set.values[i];
4685                         for(plugin = (Plugin*)plugin_set->first;
4686                                 plugin && !done;
4687                                 plugin = (Plugin*)plugin->next)
4688                         {
4689                                 plugin_dimensions(plugin, x, y, w, h);
4690                                 if(MWindowGUI::visible(x, x + w, 0, get_w()) &&
4691                                         MWindowGUI::visible(y, y + h, 0, get_h()))
4692                                 {
4693                                         if(cursor_x >= x && cursor_x < x + w &&
4694                                                 cursor_y >= y && cursor_y < y + h)
4695                                         {
4696                                                 done = 1;
4697                                                 break;
4698                                         }
4699                                 }
4700                         }
4701                 }
4702         }
4704         if(plugin)
4705         {
4706 // Start plugin popup
4707                 if(button_press)
4708                 {
4709                         if(get_buttonpress() == 3)
4710                         {
4711                                 gui->plugin_menu->update(plugin);
4712                                 gui->plugin_menu->activate_menu();
4713                                 result = 1;
4714                         } 
4715                         else
4716 // Select range of plugin on doubleclick over plugin
4717                         if (get_double_click() && !drag_start)
4718                         {
4719                                 mwindow->edl->local_session->set_selectionstart(plugin->track->from_units(plugin->startproject));
4720                                 mwindow->edl->local_session->set_selectionend(plugin->track->from_units(plugin->startproject) + 
4721                                         plugin->track->from_units(plugin->length));
4722                                 if(mwindow->edl->session->cursor_on_frames) 
4723                                 {
4724                                         mwindow->edl->local_session->set_selectionstart(
4725                                                 mwindow->edl->align_to_frame(mwindow->edl->local_session->get_selectionstart(1), 0));
4726                                         mwindow->edl->local_session->set_selectionend(
4727                                                 mwindow->edl->align_to_frame(mwindow->edl->local_session->get_selectionend(1), 1));
4728                                 }
4729                                 rerender = 1;
4730                                 redraw = 1;
4731                                 result = 1;
4732                         }
4733                 }
4734                 else
4735 // Move plugin
4736                 if(drag_start && plugin->track->record)
4737                 {
4738                         if(mwindow->edl->session->editing_mode == EDITING_ARROW)
4739                         {
4740                                 if(plugin->track->data_type == TRACK_AUDIO)
4741                                         mwindow->session->current_operation = DRAG_AEFFECT_COPY;
4742                                 else
4743                                 if(plugin->track->data_type == TRACK_VIDEO)
4744                                         mwindow->session->current_operation = DRAG_VEFFECT_COPY;
4746                                 mwindow->session->drag_plugin = plugin;
4752 // Create picon
4753                                 switch(plugin->plugin_type)
4754                                 {
4755                                         case PLUGIN_STANDALONE:
4756                                         {
4757                                                 PluginServer *server = mwindow->scan_plugindb(
4758                                                         plugin->title,
4759                                                         plugin->track->data_type);
4760                                                 if (server) 
4761                                                 {
4762                                                         VFrame *frame = server->picon;
4763 //printf("TrackCanvas::test_plugins 7\n");
4764                                                         drag_popup = new BC_DragWindow(gui, 
4765                                                                 frame, 
4766                                                                 get_abs_cursor_x(0) - frame->get_w() / 2,
4767                                                                 get_abs_cursor_y(0) - frame->get_h() / 2);
4768                                                 }
4769                                                 break;
4770                                         }
4771                                         
4772                                         case PLUGIN_SHAREDPLUGIN:
4773                                         case PLUGIN_SHAREDMODULE:
4774                                                 drag_popup = new BC_DragWindow(gui, 
4775                                                         mwindow->theme->get_image("clip_icon"), 
4776                                                         get_abs_cursor_x(0) - mwindow->theme->get_image("clip_icon")->get_w() / 2,
4777                                                         get_abs_cursor_y(0) - mwindow->theme->get_image("clip_icon")->get_h() / 2);
4778                                                 break;
4779                                 }
4782                                 result = 1;
4783                         }
4784                 }
4785         }
4787         return result;
4790 int TrackCanvas::do_transitions(int cursor_x, 
4791         int cursor_y, 
4792         int button_press,
4793         int &new_cursor,
4794         int &update_cursor)
4796         Transition *transition = 0;
4797         int result = 0;
4798         int64_t x, y, w, h;
4802         if(!mwindow->edl->session->show_assets ||
4803                 !mwindow->edl->session->auto_conf->transitions) return 0;
4804                                         
4807         for(Track *track = mwindow->edl->tracks->first;
4808                 track && !result;
4809                 track = track->next)
4810         {
4811                 for(Edit *edit = track->edits->first;
4812                         edit;
4813                         edit = edit->next)
4814                 {
4815                         if(edit->transition)
4816                         {
4817                                 edit_dimensions(edit, x, y, w, h);
4818                                 get_transition_coords(x, y, w, h);
4820                                 if(MWindowGUI::visible(x, x + w, 0, get_w()) &&
4821                                         MWindowGUI::visible(y, y + h, 0, get_h()))
4822                                 {
4823                                         if(cursor_x >= x && cursor_x < x + w &&
4824                                                 cursor_y >= y && cursor_y < y + h)
4825                                         {
4826                                                 transition = edit->transition;
4827                                                 result = 1;
4828                                                 break;
4829                                         }
4830                                 }
4831                         }
4832                 }
4833         }
4834         
4835         update_cursor = 1;
4836         if(transition)
4837         {
4838                 if(!button_press)
4839                 {
4840                         new_cursor = UPRIGHT_ARROW_CURSOR;
4841                 }
4842                 else
4843                 if(get_buttonpress() == 3)
4844                 {
4845                         gui->transition_menu->update(transition);
4846                         gui->transition_menu->activate_menu();
4847                 }
4848         }
4850         return result;
4853 int TrackCanvas::button_press_event()
4855         int result = 0;
4856         int cursor_x, cursor_y;
4857         int new_cursor, update_cursor;
4859         cursor_x = get_cursor_x();
4860         cursor_y = get_cursor_y();
4861         mwindow->session->trim_edits = 0;
4863         if(is_event_win() && cursor_inside())
4864         {
4865                 double position = (double)cursor_x * 
4866                         mwindow->edl->local_session->zoom_sample /
4867                         mwindow->edl->session->sample_rate + 
4868                         (double)mwindow->edl->local_session->view_start * 
4869                         mwindow->edl->local_session->zoom_sample /
4870                         mwindow->edl->session->sample_rate;
4873                 if(!active)
4874                 {
4875                         activate();
4876                 }
4878                 if(get_buttonpress() == 1)
4879                 {
4880                         gui->unlock_window();
4881                         gui->mbuttons->transport->handle_transport(STOP, 1);
4882                         gui->lock_window("TrackCanvas::button_press_event");
4883                 }
4885                 int update_overlay = 0, update_cursor = 0, rerender = 0;
4887                 if(get_buttonpress() == 4)
4888                 {
4889                         if(shift_down())
4890                                 mwindow->expand_sample();
4891                         else
4892                                 mwindow->move_up(get_h() / 10);
4893                         result = 1;
4894                 }
4895                 else
4896                 if(get_buttonpress() == 5)
4897                 {
4898                         if(shift_down())
4899                                 mwindow->zoom_in_sample();
4900                         else
4901                                 mwindow->move_down(get_h() / 10);
4902                         result = 1;
4903                 }
4904                 else
4905                 switch(mwindow->edl->session->editing_mode)
4906                 {
4907 // Test handles and resource boundaries and highlight a track
4908                         case EDITING_ARROW:
4909                         {
4910                                 Edit *edit;
4911                                 int handle;
4912                                 if(mwindow->edl->session->auto_conf->transitions && 
4913                                         do_transitions(cursor_x, 
4914                                                 cursor_y, 
4915                                                 1, 
4916                                                 new_cursor, 
4917                                                 update_cursor))
4918                                 {
4919                                         break;
4920                                 }
4921                                 else
4922                                 if(do_keyframes(cursor_x, 
4923                                         cursor_y, 
4924                                         0, 
4925                                         get_buttonpress(), 
4926                                         new_cursor, 
4927                                         update_cursor,
4928                                         rerender))
4929                                 {
4930                                         break;
4931                                 }
4932                                 else
4933 // Test edit boundaries
4934                                 if(do_edit_handles(cursor_x, 
4935                                         cursor_y, 
4936                                         1, 
4937                                         new_cursor, 
4938                                         update_cursor))
4939                                 {
4940                                         break;
4941                                 }
4942                                 else
4943 // Test plugin boundaries
4944                                 if(do_plugin_handles(cursor_x, 
4945                                         cursor_y, 
4946                                         1, 
4947                                         new_cursor, 
4948                                         update_cursor))
4949                                 {
4950                                         break;
4951                                 }
4952                                 else
4953                                 if(do_edits(cursor_x, cursor_y, 1, 0, update_cursor, rerender, new_cursor, update_cursor))
4954                                 {
4955                                         break;
4956                                 }
4957                                 else
4958                                 if(do_plugins(cursor_x, cursor_y, 0, 1, update_cursor, rerender))
4959                                 {
4960                                         break;
4961                                 }
4962                                 else
4963                                 if(test_resources(cursor_x, cursor_y))
4964                                 {
4965                                         break;
4966                                 }
4967                                 else
4968                                 if(do_tracks(cursor_x, cursor_y, 1))
4969                                 {
4970                                         break;
4971                                 }
4972                                 break;
4973                         }
4975 // Test handles only and select a region
4976                         case EDITING_IBEAM:
4977                         {
4978 //printf("TrackCanvas::button_press_event %d\n", position);
4980                                 if(mwindow->edl->session->auto_conf->transitions && 
4981                                         do_transitions(cursor_x, 
4982                                                 cursor_y, 
4983                                                 1, 
4984                                                 new_cursor, 
4985                                                 update_cursor))
4986                                 {
4987                                         break;
4988                                 }
4989                                 else
4990                                 if(do_keyframes(cursor_x, 
4991                                         cursor_y, 
4992                                         0, 
4993                                         get_buttonpress(), 
4994                                         new_cursor, 
4995                                         update_cursor,
4996                                         rerender))
4997                                 {
4998                                         update_overlay = 1;
4999                                         break;
5000                                 }
5001                                 else
5002 // Test edit boundaries
5003                                 if(do_edit_handles(cursor_x, 
5004                                         cursor_y, 
5005                                         1, 
5006                                         new_cursor, 
5007                                         update_cursor))
5008                                 {
5009                                         break;
5010                                 }
5011                                 else
5012 // Test plugin boundaries
5013                                 if(do_plugin_handles(cursor_x, 
5014                                         cursor_y, 
5015                                         1, 
5016                                         new_cursor, 
5017                                         update_cursor))
5018                                 {
5019                                         break;
5020                                 }
5021                                 else
5022                                 if(do_edits(cursor_x, 
5023                                         cursor_y, 
5024                                         1, 
5025                                         0, 
5026                                         update_cursor, 
5027                                         rerender, 
5028                                         new_cursor, 
5029                                         update_cursor))
5030                                 {
5031                                         break;
5032                                 }
5033                                 else
5034                                 if(do_plugins(cursor_x, 
5035                                         cursor_y, 
5036                                         0, 
5037                                         1, 
5038                                         update_cursor, 
5039                                         rerender))
5040                                 {
5041                                         break;
5042                                 }
5043                                 else
5044                                 if(do_tracks(cursor_x, cursor_y, 1))
5045                                 {
5046                                         break;
5047                                 }
5048 // Highlight selection
5049                                 else
5050                                 {
5051                                         rerender = start_selection(position);
5052                                         mwindow->session->current_operation = SELECT_REGION;
5053                                         update_cursor = 1;
5054                                 }
5056                                 break;
5057                         }
5058                 }
5061                 if(rerender)
5062                 {
5063                         gui->unlock_window();
5064                         mwindow->cwindow->update(1, 0, 0, 0, 1);
5065                         gui->lock_window("TrackCanvas::button_press_event 2");
5066 // Update faders
5067                         mwindow->update_plugin_guis();
5068                         gui->patchbay->update();
5069                 }
5071                 if(update_overlay)
5072                 {
5073                         draw_overlays();
5074                         flash();
5075                 }
5077                 if(update_cursor)
5078                 {
5079                         gui->timebar->update_highlights();
5080                         gui->cursor->hide();
5081                         gui->cursor->show();
5082                         gui->zoombar->update();
5083                         flash();
5084                         result = 1;
5085                 }
5089         }
5090         return result;
5093 int TrackCanvas::start_selection(double position)
5095         int rerender = 0;
5096         position = mwindow->edl->align_to_frame(position, 0);
5098 // Extend a border
5099         if(shift_down())
5100         {
5101                 double midpoint = (mwindow->edl->local_session->get_selectionstart(1) + 
5102                         mwindow->edl->local_session->get_selectionend(1)) / 2;
5104                 if(position < midpoint)
5105                 {
5106                         mwindow->edl->local_session->set_selectionstart(position);
5107                         selection_midpoint1 = mwindow->edl->local_session->get_selectionend(1);
5108 // Que the CWindow
5109                         rerender = 1;
5110                 }
5111                 else
5112                 {
5113                         mwindow->edl->local_session->set_selectionend(position);
5114                         selection_midpoint1 = mwindow->edl->local_session->get_selectionstart(1);
5115 // Don't que the CWindow for the end
5116                 }
5117         }
5118         else
5119 // Start a new selection
5120         {
5121 //printf("TrackCanvas::start_selection %f\n", position);
5122                 mwindow->edl->local_session->set_selectionstart(position);
5123                 mwindow->edl->local_session->set_selectionend(position);
5124                 selection_midpoint1 = position;
5125 // Que the CWindow
5126                 rerender = 1;
5127         }
5128         
5129         return rerender;
5132 void TrackCanvas::end_edithandle_selection()
5134         mwindow->modify_edithandles();
5137 void TrackCanvas::end_pluginhandle_selection()
5139         mwindow->modify_pluginhandles();
5143 double TrackCanvas::time_visible()
5145         return (double)get_w() * 
5146                 mwindow->edl->local_session->zoom_sample / 
5147                 mwindow->edl->session->sample_rate;
5190 void TrackCanvas::draw_automation()
5195 int TrackCanvas::set_index_file(int flash, Asset *asset)
5197         return 0;
5201 int TrackCanvas::button_release()
5203         return 0;
5207 int TrackCanvas::auto_reposition(int &cursor_x, int &cursor_y, int64_t cursor_position)
5209         return 0;
5213 int TrackCanvas::draw_floating_handle(int flash)
5215         return 0;
5218 int TrackCanvas::draw_loop_point(int64_t position, int flash)
5220         return 0;
5223 int TrackCanvas::draw_playback_cursor(int pixel, int flash)
5225         return 0;
5229 int TrackCanvas::update_handle_selection(int64_t cursor_position)
5231         return 0;
5234 int TrackCanvas::end_translation()
5236         return 0;