4 * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "apatchgui.inc"
25 #include "automation.h"
26 #include "bcsignals.h"
32 #include "cplayback.h"
34 #include "cwindowgui.h"
36 #include "edithandles.h"
37 #include "editpopup.h"
40 #include "edlsession.h"
41 #include "floatauto.h"
42 #include "floatautos.h"
43 #include "gwindowgui.h"
44 #include "indexstate.h"
48 #include "keyframepopup.h"
49 #include "keyframes.h"
52 #include "localsession.h"
53 #include "mainclock.h"
54 #include "maincursor.h"
55 #include "mainsession.h"
57 #include "maskautos.h"
60 #include "mwindowgui.h"
64 #include "playbackengine.h"
65 #include "playtransport.h"
67 #include "pluginpopup.h"
68 #include "pluginserver.h"
69 #include "pluginset.h"
70 #include "plugintoggles.h"
71 #include "preferences.h"
72 #include "renderengine.h"
73 #include "resourcepixmap.h"
74 #include "resourcethread.h"
77 #include "trackcanvas.h"
80 #include "transition.h"
81 #include "transitionhandles.h"
82 #include "transitionpopup.h"
83 #include "transportque.h"
85 #include "vpatchgui.inc"
91 //#define PIXMAP_AGE -5
92 #define PIXMAP_AGE -32
94 TrackCanvas::TrackCanvas(MWindow *mwindow,
105 this->mwindow = mwindow;
106 this->gui = mwindow->gui;
109 selection_midpoint = 0;
113 resource_timer = new Timer;
114 render_timer = new Timer;
115 hourglass_enabled = 0;
116 timebar_position = -1;
120 TrackCanvas::~TrackCanvas()
122 // delete transition_handles;
124 delete keyframe_pixmap;
125 delete camerakeyframe_pixmap;
126 delete modekeyframe_pixmap;
127 delete pankeyframe_pixmap;
128 delete projectorkeyframe_pixmap;
129 delete maskkeyframe_pixmap;
130 delete background_pixmap;
131 if(temp_picon) delete temp_picon;
133 delete resource_timer;
136 void TrackCanvas::create_objects()
138 background_pixmap = new BC_Pixmap(this, get_w(), get_h());
139 // transition_handles = new TransitionHandles(mwindow, this);
140 edit_handles = new EditHandles(mwindow, this);
141 keyframe_pixmap = new BC_Pixmap(this, mwindow->theme->keyframe_data, PIXMAP_ALPHA);
142 camerakeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->camerakeyframe_data, PIXMAP_ALPHA);
143 modekeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->modekeyframe_data, PIXMAP_ALPHA);
144 pankeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->pankeyframe_data, PIXMAP_ALPHA);
145 projectorkeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->projectorkeyframe_data, PIXMAP_ALPHA);
146 maskkeyframe_pixmap = new BC_Pixmap(this, mwindow->theme->maskkeyframe_data, PIXMAP_ALPHA);
152 void TrackCanvas::resize_event()
154 //printf("TrackCanvas::resize_event 1\n");
157 //printf("TrackCanvas::resize_event 2\n");
160 int TrackCanvas::keypress_event()
165 int TrackCanvas::cursor_leave_event()
167 // Because drag motion calls get_cursor_over_window we can be sure that
168 // all highlights get deleted now.
169 // This ended up blocking keyboard input from the drag operations.
170 if( timebar_position >= 0 )
172 timebar_position = -1;
174 pane->timebar->update(1);
178 // return drag_motion();
181 int TrackCanvas::drag_motion_event()
183 return gui->drag_motion();
186 int TrackCanvas::drag_motion(Track **over_track,
188 PluginSet **over_pluginset,
189 Plugin **over_plugin)
191 int cursor_x = get_relative_cursor_x();
192 int cursor_y = get_relative_cursor_y();
194 if( get_cursor_over_window() &&
195 cursor_x >= 0 && cursor_y >= 0 &&
196 cursor_x < get_w() && cursor_y < get_h() )
198 //printf("TrackCanvas::drag_motion %d %d\n", __LINE__, pane->number);
199 // Find the edit and track the cursor is over
200 for(Track *track = mwindow->edl->tracks->first; track; track = track->next)
202 int64_t track_x, track_y, track_w, track_h;
203 track_dimensions(track, track_x, track_y, track_w, track_h);
205 if(cursor_y >= track_y &&
206 cursor_y < track_y + track_h)
209 for(Edit *edit = track->edits->first; edit; edit = edit->next)
211 int64_t edit_x, edit_y, edit_w, edit_h;
212 edit_dimensions(edit, edit_x, edit_y, edit_w, edit_h);
213 if( cursor_y < edit_y || cursor_y >= edit_y + edit_h ) continue;
214 if( cursor_x >= edit_x && cursor_x < edit_x + edit_w ) {
218 if( edit != track->edits->last ) continue;
219 if( mwindow->session->current_operation != DRAG_ATRANSITION &&
220 mwindow->session->current_operation != DRAG_VTRANSITION ) continue;
221 if( !edit->silence() ) {
222 // add silence to allow drag transition past last edit
223 // will be deleted by Edits::optimize if not used
224 double length = mwindow->edl->session->default_transition_length;
225 int64_t start = edit->startproject+edit->length;
226 int64_t units = track->to_units(length, 1);
227 track->edits->create_silence(start, start+units);
230 if( cursor_x >= edit_x ) { *over_edit = edit; break; }
233 for(int i = 0; i < track->plugin_set.total; i++)
235 PluginSet *pluginset = track->plugin_set.values[i];
236 for(Plugin *plugin = (Plugin*)pluginset->first;
238 plugin = (Plugin*)plugin->next)
240 int64_t plugin_x, plugin_y, plugin_w, plugin_h;
241 plugin_dimensions(plugin, plugin_x, plugin_y, plugin_w, plugin_h);
243 if(cursor_y >= plugin_y &&
244 cursor_y < plugin_y + plugin_h)
246 *over_pluginset = plugin->plugin_set;
248 if(cursor_x >= plugin_x &&
249 cursor_x < plugin_x + plugin_w)
251 *over_plugin = plugin;
263 *over_track = pane->over_patchbay();
269 int TrackCanvas::drag_stop_event()
271 int result = gui->drag_stop();
272 if( !result && mwindow->session->current_operation ) {
273 mwindow->session->current_operation = NO_OPERATION;
279 int TrackCanvas::drag_stop(int *redraw)
284 int cursor_x = -1, cursor_y = -1;
286 if( get_cursor_over_window() ) {
287 if( (cursor_x = get_relative_cursor_x()) >= 0 && cursor_x < get_w() &&
288 (cursor_y = get_relative_cursor_y()) >= 0 && cursor_y < get_h() )
291 Track *track = pane->over_patchbay();
292 if( track && mwindow->session->track_highlighted == track )
298 switch(mwindow->session->current_operation) {
299 case DRAG_VTRANSITION:
300 case DRAG_ATRANSITION:
301 if(mwindow->session->edit_highlighted) {
302 if( (mwindow->session->current_operation == DRAG_ATRANSITION &&
303 mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
304 (mwindow->session->current_operation == DRAG_VTRANSITION &&
305 mwindow->session->track_highlighted->data_type == TRACK_VIDEO) ) {
306 mwindow->session->current_operation = NO_OPERATION;
307 mwindow->paste_transition();
314 // Behavior for dragged plugins is limited by the fact that a shared plugin
315 // can only refer to a standalone plugin that exists in the same position in
316 // time. Dragging a plugin from one point in time to another can't produce
317 // a shared plugin to the original plugin. In this case we relocate the
318 // plugin instead of sharing it.
319 case DRAG_AEFFECT_COPY:
320 case DRAG_VEFFECT_COPY:
321 if( mwindow->session->track_highlighted &&
322 ((mwindow->session->current_operation == DRAG_AEFFECT_COPY &&
323 mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
324 (mwindow->session->current_operation == DRAG_VEFFECT_COPY &&
325 mwindow->session->track_highlighted->data_type == TRACK_VIDEO)) ) {
326 mwindow->session->current_operation = NO_OPERATION;
328 int64_t drop_position = -1;
329 Plugin *drag_plugin = mwindow->session->drag_plugin;
330 PluginSet *hi_plugin_set = mwindow->session->pluginset_highlighted;
331 Track *hi_track = mwindow->session->track_highlighted;
333 // Insert shared plugin in source
334 // Move source to different location
335 if( hi_plugin_set && hi_plugin_set->track == drag_plugin->track ) {
336 //printf("TrackCanvas::drag_stop 6\n");
337 drop_position = drop_plugin_position(hi_plugin_set, drag_plugin);
338 if( drop_position < 0 ) {
340 break; // Do not do anything
343 Track *track = mwindow->session->track_highlighted;
344 drop_position = track->frame_align(drop_position, 0);
345 mwindow->move_effect(drag_plugin, hi_plugin_set, drop_position);
348 else if( hi_track ) {
349 // Put it in a new plugin set determined by an edit boundary, or at the start of the track
350 Edit *hi_edit = mwindow->session->edit_highlighted;
351 drop_position = hi_edit ? hi_edit->startproject : 0;
352 if( drop_position < 0 ) {
354 break; // Do not do anything
357 Track *track = mwindow->session->track_highlighted;
358 drop_position = track->frame_align(drop_position, 0);
359 mwindow->move_effect(drag_plugin, hi_track, drop_position);
367 if( mwindow->session->track_highlighted &&
368 ((mwindow->session->current_operation == DRAG_AEFFECT &&
369 mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
370 (mwindow->session->current_operation == DRAG_VEFFECT &&
371 mwindow->session->track_highlighted->data_type == TRACK_VIDEO)) ) {
372 // Drop all the effects
373 PluginSet *plugin_set = mwindow->session->pluginset_highlighted;
374 Track *track = mwindow->session->track_highlighted;
376 double length = track->get_length();
378 if(mwindow->session->plugin_highlighted) {
379 start = track->from_units(mwindow->session->plugin_highlighted->startproject);
380 length = track->from_units(mwindow->session->plugin_highlighted->length);
381 if(length <= 0) length = track->get_length();
383 else if(mwindow->session->pluginset_highlighted) {
384 start = track->from_units(plugin_set->length());
385 length = track->get_length() - start;
386 if(length <= 0) length = track->get_length();
388 else if(mwindow->edl->local_session->get_selectionend() >
389 mwindow->edl->local_session->get_selectionstart()) {
390 start = mwindow->edl->local_session->get_selectionstart();
391 length = mwindow->edl->local_session->get_selectionend() -
392 mwindow->edl->local_session->get_selectionstart();
394 // Move to a point between two edits
395 else if(mwindow->session->edit_highlighted) {
396 start = mwindow->session->track_highlighted->from_units(
397 mwindow->session->edit_highlighted->startproject);
398 length = mwindow->session->track_highlighted->from_units(
399 mwindow->session->edit_highlighted->length);
401 start = mwindow->edl->align_to_frame(start, 0);
402 mwindow->insert_effects_canvas(start, length);
405 if( mwindow->session->track_highlighted )
406 result = 1; // we have to cleanup
410 if(mwindow->session->track_highlighted) {
411 double asset_duration = 0;
412 int64_t asset_length_units = 0;
414 if(mwindow->session->current_operation == DRAG_ASSET &&
415 mwindow->session->drag_assets->total) {
416 Indexable *indexable = mwindow->session->drag_assets->values[0];
417 // we use video if we are over video and audio if we are over audio
418 if( indexable->have_video() &&
419 mwindow->session->track_highlighted->data_type == TRACK_VIDEO ) {
420 // Images have length -1
421 int64_t video_length = indexable->get_video_frames();
422 if (video_length < 0) {
423 if(mwindow->edl->session->si_useduration)
424 video_length = mwindow->edl->session->si_duration;
426 video_length = 1.0 / mwindow->edl->session->frame_rate ;
428 asset_duration = video_length / indexable->get_frame_rate();
430 else if( indexable->have_audio() &&
431 mwindow->session->track_highlighted->data_type == TRACK_AUDIO ) {
432 int64_t audio_length = indexable->get_audio_samples();
433 asset_duration = (double)audio_length / indexable->get_sample_rate();
437 break; // Do not do anything
440 else if( mwindow->session->current_operation == DRAG_ASSET &&
441 mwindow->session->drag_clips->total ) {
442 EDL *clip = mwindow->session->drag_clips->values[0];
443 asset_duration = clip->tracks->total_length();
446 printf("DRAG_ASSET error: Asset dropped, but both drag_clips and drag_assets total is zero\n");
449 asset_length_units = mwindow->session->track_highlighted->to_units(asset_duration, 1);
450 int64_t drop_position = drop_edit_position (&insertion, NULL, asset_length_units);
451 if( drop_position < 0 ) {
453 break; // Do not do anything
456 Track *track = mwindow->session->track_highlighted;
457 double track_position = track->from_units(drop_position);
458 track_position = mwindow->edl->align_to_frame(track_position, 0);
461 // // FIXME, we should create an mwindow/EDL method that overwrites, without clearing the keyframes and autos
462 // // Unfortunately, this is _a lot_ of work to do right
463 // printf("Problematic insertion\n");
464 // mwindow->edl->tracks->clear(track_position,
465 // track_position + asset_duration, 0);
467 mwindow->paste_assets(track_position, track, !insertion);
468 result = 1; // need to be one no matter what, since we have track highlited so we have to cleanup....
473 mwindow->session->current_operation = NO_OPERATION;
474 if(mwindow->session->track_highlighted) {
475 if( mwindow->session->track_highlighted->data_type ==
476 mwindow->session->drag_edit->track->data_type) {
477 int64_t drop_position = drop_edit_position(&insertion,
478 mwindow->session->drag_edit,
479 mwindow->session->drag_edit->length);
480 if( drop_position < 0 ) {
482 break; // Do not do anything
484 Track *track = mwindow->session->track_highlighted;
485 double track_position = track->from_units(drop_position);
486 track_position = mwindow->edl->align_to_frame(track_position, 0);
487 mwindow->move_edits(mwindow->session->drag_edits,
488 track, track_position, !insertion);
500 int TrackCanvas::drag_start_event()
505 int new_cursor, update_cursor;
507 if(mwindow->session->current_operation != NO_OPERATION) return 0;
510 if(do_plugins(get_drag_x(), get_drag_y(),
511 1, 0, redraw, rerender)) {
514 else if(do_edits(get_drag_x(), get_drag_y(),
515 0, 1, redraw, rerender, new_cursor, update_cursor)) {
523 int64_t TrackCanvas::drop_edit_position(int *is_insertion, Edit *moved_edit, int64_t moved_edit_length)
525 // get the canvas/track position
526 Track *track = mwindow->session->track_highlighted;
527 int cursor_x = get_relative_cursor_x();
528 double zoom_scale = (double)mwindow->edl->session->sample_rate / mwindow->edl->local_session->zoom_sample;
529 double cur_pos = (cursor_x + mwindow->edl->local_session->view_start[pane->number]) / zoom_scale;
530 double position = mwindow->edl->align_to_frame(cur_pos, 1);
531 if( position <= 0 ) {
535 double cursor_position = position;
536 int64_t drop_position = track->to_units(cursor_position, 1);
537 if( moved_edit ) { // relative cursor position depends upon drop point
538 double moved_edit_start = moved_edit->track->from_units(moved_edit->startproject);
539 position -= mwindow->session->drag_position - moved_edit_start;
541 int64_t edit_position = track->to_units(position, 1);
542 int64_t grab_position = edit_position;
543 if( !moved_edit ) // for clips and assets acts as they were grabbed in the middle
544 grab_position -= moved_edit_length / 2;
545 Edit *last_edit = track->edits->last;
546 if( !last_edit || edit_position >= (last_edit->startproject+last_edit->length) ) {
548 return grab_position;
551 int64_t drop_start = 0, drop_end = 0; // drop zone boundries
552 Edit *next_edit = track->edits->first;
554 Edit *edit = next_edit; next_edit = (Edit *)edit->next;
555 int64_t edit_start = edit->startproject;
556 int64_t edit_end = edit_start + edit->length;
557 double edit_start_pos = edit->track->from_units(edit_start);
558 if( (fabs(edit_start_pos-cursor_position)*zoom_scale) < HANDLE_W ) {
559 *is_insertion = 1; // cursor is close to the beginning of an edit -> insertion
562 double edit_end_pos = edit->track->from_units(edit_end);
563 if( (fabs(edit_end_pos-cursor_position)*zoom_scale) < HANDLE_W ) {
564 *is_insertion = 1; // cursor is close to the end of an edit -> insertion
567 if( edit != moved_edit && !edit->silence() )
568 drop_start = edit_end; // reset drop zone
570 if( next_edit == moved_edit || next_edit->silence() ) continue;
574 drop_end = INT64_MAX;
575 if( edit_position >= drop_start &&
576 edit_position+moved_edit_length < drop_end ) {
577 *is_insertion = 0; // fits in the zone
578 return edit_position;
580 if( drop_position < drop_end ) { // drop in the zone
581 if( (drop_end - drop_start) >= moved_edit_length ) {
582 *is_insertion = 0; // fits in the zone, but over the edge
583 int64_t dx0 = llabs(drop_position - drop_start);
584 int64_t dx1 = llabs(drop_position - drop_end);
585 return dx0 < dx1 ? drop_start : drop_end - moved_edit_length;
588 int64_t edit_center = (edit_start + edit_end) / 2;
589 return position < edit_center ? drop_start : drop_end;
597 int64_t TrackCanvas::drop_plugin_position(PluginSet *plugin_set, Plugin *moved_plugin)
599 // get the canvas/track position
600 Track *track = plugin_set->track;
601 double moved_plugin_length = moved_plugin->track->from_units(moved_plugin->length);
602 int64_t track_plugin_length = track->to_units(moved_plugin_length, 0);
603 int cursor_x = get_relative_cursor_x();
604 double zoom_scale = (double)mwindow->edl->session->sample_rate / mwindow->edl->local_session->zoom_sample;
605 double cur_pos = (cursor_x + mwindow->edl->local_session->view_start[pane->number]) / zoom_scale;
606 double position = mwindow->edl->align_to_frame(cur_pos, 1);
607 if( position <= 0 ) return 0;
608 int64_t drop_position = track->to_units(position, 1);
609 Plugin *last_plugin = (Plugin *)plugin_set->last;
610 if( !last_plugin ) return drop_position;
611 double plugin_set_end = last_plugin->track->from_units(last_plugin->startproject+last_plugin->length);
612 if( position >= plugin_set_end ) return drop_position;
613 double moved_plugin_start = moved_plugin->track->from_units(moved_plugin->startproject);
614 position -= mwindow->session->drag_position - moved_plugin_start;
615 int64_t plugin_position = track->to_units(position, 1);
617 int64_t drop_start = 0, drop_end = 0; // drop zone boundries
618 Plugin *next_plugin = (Plugin *)plugin_set->first;
619 while( next_plugin ) {
620 Plugin *plugin = next_plugin; next_plugin = (Plugin *)plugin->next;
621 int64_t plugin_start = plugin->startproject;
622 int64_t plugin_end = plugin_start + plugin->length;
623 double plugin_end_pos = plugin->track->from_units(plugin_end);
624 int64_t track_plugin_end = track->to_units(plugin_end_pos, 0);
625 if( plugin != moved_plugin && !plugin->silence() )
626 drop_start = track_plugin_end;
628 if( next_plugin == moved_plugin || next_plugin->silence() ) continue;
629 drop_end = track_plugin_end;
632 drop_end = INT64_MAX;
633 if( plugin_position >= drop_start && // fits in the zone
634 plugin_position+track_plugin_length < drop_end ) {
635 return plugin_position;
637 if( drop_position < drop_end ) { // drop in the zone
638 if( (drop_end - drop_start) >= track_plugin_length ) {
639 int64_t dx0 = llabs(drop_position - drop_start);
640 int64_t dx1 = llabs(drop_position - drop_end);
641 return dx0 < dx1 ? drop_start : drop_end - track_plugin_length;
649 void TrackCanvas::draw(int mode, int hide_cursor)
654 // Swap pixmap layers
655 if(get_w() != background_pixmap->get_w() ||
656 get_h() != background_pixmap->get_h())
658 delete background_pixmap;
659 background_pixmap = new BC_Pixmap(this, get_w(), get_h());
662 // Cursor disappears after resize when this is called.
663 // Cursor doesn't redraw after editing when this isn't called.
664 if(pane->cursor && hide_cursor) pane->cursor->hide();
665 draw_top_background(get_parent(), 0, 0, get_w(), get_h(), background_pixmap);
667 if(debug) PRINT_TRACE
668 draw_resources(mode);
670 if(debug) PRINT_TRACE
672 if(debug) PRINT_TRACE
675 void TrackCanvas::update_cursor(int flush)
677 switch(mwindow->edl->session->editing_mode)
679 case EDITING_ARROW: set_cursor(ARROW_CURSOR, 0, flush); break;
680 case EDITING_IBEAM: set_cursor(IBEAM_CURSOR, 0, flush); break;
685 void TrackCanvas::test_timer()
687 if(resource_timer->get_difference() > 1000 &&
691 hourglass_enabled = 1;
696 void TrackCanvas::draw_indexes(Indexable *indexable)
698 IndexState *index_state = indexable->index_state;
699 // Don't redraw raw samples
700 if(index_state->index_zoom > mwindow->edl->local_session->zoom_sample)
702 draw_resources(0, 1, indexable);
707 void TrackCanvas::draw_resources(int mode,
709 Indexable *indexable)
713 if(debug) PRINT_TRACE
715 // can't stop thread here, because this is called for every pane
716 // if(mode != IGNORE_THREAD && !indexes_only)
717 // gui->resource_thread->stop_draw(!indexes_only);
719 if(mode != IGNORE_THREAD &&
721 !gui->resource_thread->interrupted)
723 printf("TrackCanvas::draw_resources %d: called without stopping ResourceThread\n",
726 BC_Signals::dump_stack();
729 if(debug) PRINT_TRACE
731 resource_timer->update();
733 // Age resource pixmaps for deletion
735 for(int i = 0; i < gui->resource_pixmaps.total; i++)
736 gui->resource_pixmaps.values[i]->visible--;
738 if(mode == FORCE_REDRAW)
739 gui->resource_pixmaps.remove_all_objects();
741 if(debug) PRINT_TRACE
744 for(Track *current = mwindow->edl->tracks->first;
748 if(debug) PRINT_TRACE
749 for(Edit *edit = current->edits->first; edit; edit = edit->next)
751 if(debug) PRINT_TRACE
752 if( current->data_type != TRACK_SUBTITLE )
753 if(!edit->asset && !edit->nested_edl) continue;
756 if(edit->track->data_type != TRACK_AUDIO) continue;
758 if(edit->nested_edl &&
759 strcmp(indexable->path, edit->nested_edl->path)) continue;
762 strcmp(indexable->path, edit->asset->path)) continue;
765 if(debug) PRINT_TRACE
767 int64_t edit_x, edit_y, edit_w, edit_h;
768 edit_dimensions(edit, edit_x, edit_y, edit_w, edit_h);
771 if(MWindowGUI::visible(edit_x, edit_x + edit_w, 0, get_w()) &&
772 MWindowGUI::visible(edit_y, edit_y + edit_h, 0, get_h()))
774 int64_t pixmap_x, pixmap_w, pixmap_h;
775 if(debug) PRINT_TRACE
777 // Search for existing pixmap containing edit
778 for(int i = 0; i < gui->resource_pixmaps.total; i++)
780 ResourcePixmap* pixmap = gui->resource_pixmaps.values[i];
781 // Same pointer can be different edit if editing took place
782 if(pixmap->edit_id == edit->id &&
783 pixmap->pane_number == pane->number)
789 if(debug) PRINT_TRACE
791 // Get new size, offset of pixmap needed
792 get_pixmap_size(edit,
798 if(debug) PRINT_TRACE
801 if(pixmap_w && pixmap_h)
803 // Create pixmap if it doesn't exist
804 ResourcePixmap* pixmap = create_pixmap(edit, edit_x,
805 pixmap_x, pixmap_w, pixmap_h);
806 // Resize it if it's bigger
807 if( pixmap_w > pixmap->pixmap_w ||
808 pixmap_h > pixmap->pixmap_h)
809 pixmap->resize(pixmap_w, pixmap_h);
810 pixmap->update_settings(edit, edit_x, edit_w,
811 pixmap_x, pixmap_w, pixmap_h);
813 if( current->show_assets() )
814 pixmap->draw_data(this,
815 edit, edit_x, edit_w,
816 pixmap_x, pixmap_w, pixmap_h,
820 clear_box(0,0, pixmap_w,pixmap_h, pixmap);
823 if( current->show_titles() )
824 pixmap->draw_title(this,
825 edit, edit_x, edit_w,
827 // Resize it if it's smaller
828 if(pixmap_w < pixmap->pixmap_w ||
829 pixmap_h < pixmap->pixmap_h)
830 pixmap->resize(pixmap_w, pixmap_h);
832 // Copy pixmap to background canvas
833 background_pixmap->draw_pixmap(pixmap,
835 current->y_pixel - mwindow->edl->local_session->track_start[pane->number],
839 if(debug) PRINT_TRACE
846 // Delete unused pixmaps
847 if(debug) PRINT_TRACE
849 for(int i = gui->resource_pixmaps.total - 1; i >= 0; i--)
850 if(gui->resource_pixmaps.values[i]->visible < PIXMAP_AGE)
852 //printf("TrackCanvas::draw_resources %d\n", __LINE__);
853 delete gui->resource_pixmaps.values[i];
854 gui->resource_pixmaps.remove(gui->resource_pixmaps.values[i]);
856 if(debug) PRINT_TRACE
858 if(hourglass_enabled)
861 hourglass_enabled = 0;
863 if(debug) PRINT_TRACE
865 // can't stop thread here, because this is called for every pane
866 // if(mode != IGNORE_THREAD && !indexes_only)
867 // gui->resource_thread->start_draw();
868 if(debug) PRINT_TRACE
873 ResourcePixmap* TrackCanvas::create_pixmap(Edit *edit,
879 ResourcePixmap *result = 0;
881 for(int i = 0; i < gui->resource_pixmaps.total; i++)
883 //printf("TrackCanvas::create_pixmap 1 %d %d\n", edit->id, resource_pixmaps.values[i]->edit->id);
884 if(gui->resource_pixmaps.values[i]->edit_id == edit->id &&
885 gui->resource_pixmaps.values[i]->pane_number == pane->number)
887 result = gui->resource_pixmaps.values[i];
895 result = new ResourcePixmap(mwindow,
902 gui->resource_pixmaps.append(result);
905 // result->resize(pixmap_w, pixmap_h);
909 void TrackCanvas::get_pixmap_size(Edit *edit,
917 // Align x on frame boundaries
920 // switch(edit->edits->track->data_type)
932 if(pixmap_x + pixmap_w > get_w())
934 pixmap_w = get_w() - pixmap_x;
941 // int64_t picon_w = (int64_t)(edit->picon_w() + 0.5);
942 // int64_t frame_w = (int64_t)(edit->frame_w() + 0.5);
943 // int64_t pixel_increment = MAX(picon_w, frame_w);
944 // int64_t pixmap_x1 = edit_x;
945 // int64_t pixmap_x2 = edit_x + edit_w;
949 // pixmap_x1 = (int64_t)((double)-edit_x / pixel_increment) *
954 // if(pixmap_x2 > get_w())
956 // pixmap_x2 = (int64_t)((double)(get_w() - edit_x) / pixel_increment + 1) *
960 // pixmap_x = pixmap_x1;
961 // pixmap_w = pixmap_x2 - pixmap_x1;
966 pixmap_h = mwindow->edl->local_session->zoom_track;
967 Track *track = edit->edits->track;
968 if( track->show_titles() )
969 pixmap_h += mwindow->theme->get_image("title_bg_data")->get_h();
970 //printf("get_pixmap_size %d %d %d %d\n", edit_x, edit_w, pixmap_x, pixmap_w);
973 void TrackCanvas::edit_dimensions(Edit *edit,
974 int64_t &x, int64_t &y, int64_t &w, int64_t &h)
976 x = Units::round(edit->track->from_units(edit->startproject) *
977 mwindow->edl->session->sample_rate /
978 mwindow->edl->local_session->zoom_sample -
979 mwindow->edl->local_session->view_start[pane->number]);
981 y = edit->edits->track->y_pixel - mwindow->edl->local_session->track_start[pane->number];
983 // Method for calculating w so when edits are together we never get off by one error due to rounding
984 int64_t x_next = Units::round(edit->track->from_units(edit->startproject + edit->length) *
985 mwindow->edl->session->sample_rate /
986 mwindow->edl->local_session->zoom_sample -
987 mwindow->edl->local_session->view_start[pane->number]);
991 if( edit->track->show_titles() )
992 edit_h += mwindow->theme->get_image("title_bg_data")->get_h();
993 if( edit->track->show_assets() )
994 edit_h += resource_h();
998 void TrackCanvas::track_dimensions(Track *track, int64_t &x, int64_t &y, int64_t &w, int64_t &h)
1002 y = track->y_pixel - mwindow->edl->local_session->track_start[pane->number];
1003 h = track->vertical_span(mwindow->theme);
1007 void TrackCanvas::draw_paste_destination()
1009 //int cursor_x = get_relative_cursor_x();
1010 //int cursor_y = get_relative_cursor_y();
1011 int current_atrack = 0;
1012 int current_vtrack = 0;
1013 int current_aedit = 0;
1014 int current_vedit = 0;
1020 //if(pane->number == BOTTOM_RIGHT_PANE)
1021 //printf("TrackCanvas::draw_paste_destination %d %p\n", __LINE__, mwindow->session->track_highlighted);
1023 if((mwindow->session->current_operation == DRAG_ASSET &&
1024 (mwindow->session->drag_assets->total ||
1025 mwindow->session->drag_clips->total)) ||
1026 (mwindow->session->current_operation == DRAG_EDIT &&
1027 mwindow->session->drag_edits->total)) {
1028 Indexable *indexable = 0;
1032 if(mwindow->session->current_operation == DRAG_ASSET &&
1033 mwindow->session->drag_assets->size())
1034 indexable = mwindow->session->drag_assets->get(0);
1036 if(mwindow->session->current_operation == DRAG_ASSET &&
1037 mwindow->session->drag_clips->size())
1038 clip = mwindow->session->drag_clips->get(0);
1040 int has_audio = 0, has_video = 0;
1041 double paste_audio_length = 0, paste_video_length = 0;
1042 double paste_audio_position = -1, paste_video_position = -1;
1045 has_audio = indexable->have_audio();
1046 paste_audio_length = !has_audio ? 0 :
1047 (double)indexable->get_audio_samples() / indexable->get_sample_rate();
1048 has_video = indexable->have_video();
1049 Asset *asset = indexable->is_asset ? (Asset *)indexable : 0;
1050 // Images have length -1
1051 if( asset && asset->video_data && asset->video_length < 0 ) {
1052 paste_video_length = mwindow->edl->session->si_useduration ?
1053 mwindow->edl->session->si_duration / asset->frame_rate :
1054 1.0 / asset->frame_rate ; // 1 frame
1057 paste_video_length = !has_video ? 0 :
1058 (double)indexable->get_video_frames() / indexable->get_frame_rate();
1062 has_audio = clip->tracks->total_audio_tracks() > 0 ? 1 : 0;
1063 paste_audio_length = !has_audio ? 0 : clip->tracks->total_audio_length();
1064 has_video = clip->tracks->total_video_tracks() > 0 ? 1 : 0;
1065 paste_video_length = !has_video ? 0 : clip->tracks->total_video_length();
1068 // 'Align cursor on frame' lengths calculations
1069 if( mwindow->edl->session->cursor_on_frames ) {
1070 double fps = mwindow->edl->session->frame_rate;
1071 double aud = floor(paste_audio_length * fps) / fps;
1072 double vid = floor(paste_video_length * fps) / fps;
1073 double length = has_video && has_audio ?
1074 aud < vid ? aud : vid :
1076 has_audio ? aud : 0;
1077 paste_video_length = paste_audio_length = length;
1080 if( has_audio ) { // we use video if we are over video and audio if we are over audio
1082 switch( mwindow->session->track_highlighted->data_type ) {
1083 case TRACK_VIDEO: length = paste_video_length; break;
1084 case TRACK_AUDIO: length = paste_audio_length; break;
1086 int64_t asset_length = mwindow->session->track_highlighted->
1087 to_units(length, 1);
1088 paste_audio_position = mwindow->session->track_highlighted->
1089 from_units(drop_edit_position(&insertion, NULL, asset_length));
1092 int64_t asset_length = mwindow->session->track_highlighted->
1093 to_units(paste_video_length, 1);
1094 paste_video_position = mwindow->session->track_highlighted->
1095 from_units(drop_edit_position(&insertion, NULL, asset_length));
1098 // Get destination track
1099 for(Track *dest = mwindow->session->track_highlighted;
1101 dest = dest->next) {
1103 // Get source width in pixels
1105 // Use start of highlighted edit
1106 if(mwindow->session->edit_highlighted) {
1107 position = mwindow->session->track_highlighted->from_units(
1108 mwindow->session->edit_highlighted->startproject);
1111 // Use end of highlighted track, disregarding effects
1112 position = mwindow->session->track_highlighted->from_units(
1113 mwindow->session->track_highlighted->edits->length());
1116 // Get the x coordinate
1117 x = Units::to_int64(position *
1118 mwindow->edl->session->sample_rate /
1119 mwindow->edl->local_session->zoom_sample) -
1120 mwindow->edl->local_session->view_start[pane->number];
1122 double paste_position = -1.;
1123 if(dest->data_type == TRACK_AUDIO) {
1124 if(indexable && current_atrack < indexable->get_audio_channels()) {
1125 //printf("TrackCanvas::draw_paste_destination %d %d\n", __LINE__, current_atrack);
1126 w = Units::to_int64((double)indexable->get_audio_samples() /
1127 indexable->get_sample_rate() *
1128 mwindow->edl->session->sample_rate /
1129 mwindow->edl->local_session->zoom_sample);
1130 paste_position = paste_audio_position;
1132 else if(clip && current_atrack < clip->tracks->total_audio_tracks()) {
1133 w = Units::to_int64((double)clip->tracks->total_length() *
1134 mwindow->edl->session->sample_rate /
1135 mwindow->edl->local_session->zoom_sample);
1136 paste_position = paste_audio_position;
1137 //printf("draw_paste_destination %d\n", x);
1139 else if(mwindow->session->current_operation == DRAG_EDIT &&
1140 current_aedit < mwindow->session->drag_edits->total) {
1142 while(current_aedit < mwindow->session->drag_edits->total &&
1143 mwindow->session->drag_edits->values[current_aedit]->track->data_type != TRACK_AUDIO)
1146 if(current_aedit < mwindow->session->drag_edits->total) {
1147 edit = mwindow->session->drag_edits->values[current_aedit];
1148 w = Units::to_int64(edit->length / mwindow->edl->local_session->zoom_sample);
1149 paste_position = mwindow->session->track_highlighted->
1150 from_units(drop_edit_position(&insertion,
1151 mwindow->session->drag_edit,
1152 mwindow->session->drag_edit->length));
1156 if( paste_position >= 0 ) {
1157 position = paste_position;
1164 else if(dest->data_type == TRACK_VIDEO) {
1165 //printf("draw_paste_destination 1\n");
1166 if(indexable && current_vtrack < indexable->get_video_layers())
1168 w = Units::to_int64((double)indexable->get_video_frames() /
1169 indexable->get_frame_rate() *
1170 mwindow->edl->session->sample_rate /
1171 mwindow->edl->local_session->zoom_sample);
1172 paste_position = paste_video_position;
1174 else if(clip && current_vtrack < clip->tracks->total_video_tracks()) {
1175 w = Units::to_int64(clip->tracks->total_length() *
1176 mwindow->edl->session->sample_rate /
1177 mwindow->edl->local_session->zoom_sample);
1178 paste_position = paste_video_position;
1180 else if(mwindow->session->current_operation == DRAG_EDIT &&
1181 current_vedit < mwindow->session->drag_edits->total) {
1183 while(current_vedit < mwindow->session->drag_edits->total &&
1184 mwindow->session->drag_edits->values[current_vedit]->track->data_type != TRACK_VIDEO)
1187 if(current_vedit < mwindow->session->drag_edits->total) {
1188 edit = mwindow->session->drag_edits->values[current_vedit];
1189 w = Units::to_int64(edit->track->from_units(edit->length) *
1190 mwindow->edl->session->sample_rate /
1191 mwindow->edl->local_session->zoom_sample);
1192 paste_position = mwindow->session->track_highlighted->
1193 from_units(drop_edit_position(&insertion,
1194 mwindow->session->drag_edit,
1195 mwindow->session->drag_edit->length));
1198 if( paste_position >= 0 ) {
1199 position = paste_position;
1208 // Get the x coordinate
1209 x = Units::to_int64(position *
1210 mwindow->edl->session->sample_rate /
1211 mwindow->edl->local_session->zoom_sample) -
1212 mwindow->edl->local_session->view_start[pane->number];
1213 int y = dest->y_pixel - mwindow->edl->local_session->track_start[pane->number];
1214 int h = dest->vertical_span(mwindow->theme);
1216 //printf("TrackCanvas::draw_paste_destination 2 %d %d %d %d\n", x, y, w, h);
1217 if(x < -BC_INFINITY) {
1218 w -= -BC_INFINITY - x;
1219 x += -BC_INFINITY - x;
1222 // if(pane->number == TOP_RIGHT_PANE)
1223 // printf("TrackCanvas::draw_paste_destination %d %d %d %d %d\n",
1224 // __LINE__, x, y, w, h);
1226 draw_highlight_insertion(x, y, w, h);
1228 draw_highlight_rectangle(x, y, w, h);
1235 void TrackCanvas::plugin_dimensions(Plugin *plugin, int64_t &x, int64_t &y, int64_t &w, int64_t &h)
1237 x = Units::round(plugin->track->from_units(plugin->startproject) *
1238 mwindow->edl->session->sample_rate /
1239 mwindow->edl->local_session->zoom_sample -
1240 mwindow->edl->local_session->view_start[pane->number]);
1241 w = Units::round(plugin->track->from_units(plugin->length) *
1242 mwindow->edl->session->sample_rate /
1243 mwindow->edl->local_session->zoom_sample);
1244 y = plugin->track->y_pixel
1245 - mwindow->edl->local_session->track_start[pane->number];
1246 if( plugin->track->show_titles() )
1247 y += mwindow->theme->get_image("title_bg_data")->get_h();
1248 if( plugin->track->show_assets() )
1250 y += plugin->plugin_set->get_number() *
1251 mwindow->theme->get_image("plugin_bg_data")->get_h();
1252 h = mwindow->theme->get_image("plugin_bg_data")->get_h();
1255 int TrackCanvas::resource_h()
1257 return mwindow->edl->local_session->zoom_track;
1260 void TrackCanvas::draw_highlight_rectangle(int x, int y, int w, int h)
1263 // if we have to draw a highlighted rectangle completely on the left or completely on the right of the viewport,
1264 // just draw arrows, so user has indication that something is there
1265 // FIXME: get better colors
1269 draw_triangle_left(0, y + h /6, h * 2/3, h * 2/3, BLACK, GREEN, YELLOW, RED, BLUE);
1274 draw_triangle_right(get_w() - h * 2/3, y + h /6, h * 2/3, h * 2/3, BLACK, GREEN, YELLOW, RED, BLUE);
1278 // Fix bug in heroines & cvs version as of 22.8.2005:
1279 // If we grab when zoomed in and zoom out while dragging, when edit gets really narrow strange things start happening
1280 if (w >= 0 && w < 3) {x -= w /2; w = 3;};
1293 w = MIN(w, get_w() + 20);
1294 h = MIN(h, get_h() + 20);
1297 set_color(mwindow->preferences->highlight_inverse);
1299 //draw_rectangle(x, y, w, h);
1300 draw_rectangle(x + 1, y + 1, w - 2, h - 2);
1301 draw_rectangle(x + 2, y + 2, w - 4, h - 4);
1303 draw_rectangle(x, y, w, h);
1305 //if(pane->number == TOP_RIGHT_PANE)
1306 //printf("TrackCanvas::draw_highlight_rectangle %d %d %d %d %d\n", __LINE__, x, y, w, h);
1309 void TrackCanvas::draw_highlight_insertion(int x, int y, int w, int h)
1312 // if we have to draw a highlighted rectangle completely on the left or completely on the right of the viewport,
1313 // just draw arrows, so user has indication that something is there
1314 // FIXME: get better colors
1323 /* these don't look so good
1325 draw_line(x, y, x, y+h);
1326 draw_line(x - h2 * 2, y + h1*2, x - h2, y+h1*2);
1327 draw_line(x - h2 * 2, y + h1*2+1, x - h2, y+h1*2+1);
1328 draw_line(x - h2 * 2, y + h1*6, x - h2, y+h1*6);
1329 draw_line(x - h2 * 2, y + h1*6+1, x - h2, y+h1*6+1);
1331 draw_triangle_right(x - h2, y + h1, h2, h2, BLACK, GREEN, YELLOW, RED, BLUE);
1332 draw_triangle_right(x - h2, y + h1*5, h2, h2, BLACK, GREEN, YELLOW, RED, BLUE);
1334 /* draw_line(x + h2 * 2, y + h1*2, x + h2, y+h1*2);
1335 draw_line(x + h2 * 2, y + h1*2+1, x + h2, y+h1*2+1);
1336 draw_line(x + h2 * 2, y + h1*6, x + h2, y+h1*6);
1337 draw_line(x - h2 * 2, y + h1*6+1, x + h2, y+h1*6+1);
1339 draw_triangle_left(x, y + h1, h2, h2, BLACK, GREEN, YELLOW, RED, BLUE);
1340 draw_triangle_left(x, y + h1*5, h2, h2, BLACK, GREEN, YELLOW, RED, BLUE);
1342 // draw the box centred around x
1344 // Fix bug in heroines & cvs version as of 22.8.2005:
1345 // If we grab when zoomed in and zoom out while dragging, when edit gets really narrow strange things start happening
1346 if (w >= 0 && w < 3) {x -= w /2; w = 3;};
1357 w = MIN(w, get_w() + 20);
1358 h = MIN(h, get_h() + 20);
1359 set_color(mwindow->preferences->highlight_inverse);
1361 draw_rectangle(x, y, w, h);
1362 draw_rectangle(x + 1, y + 1, w - 2, h - 2);
1364 //printf("TrackCanvas::draw_highlight_insertion %d %d %d %d\n", x, y, w, h);
1367 void TrackCanvas::draw_playback_cursor()
1369 // Called before playback_cursor exists
1370 // if(mwindow->playback_cursor && mwindow->playback_cursor->visible)
1372 // mwindow->playback_cursor->visible = 0;
1373 // mwindow->playback_cursor->draw();
1377 void TrackCanvas::get_handle_coords(Edit *edit, int64_t &x, int64_t &y, int64_t &w, int64_t &h, int side)
1379 int handle_w = mwindow->theme->edithandlein_data[0]->get_w();
1380 int handle_h = mwindow->theme->edithandlein_data[0]->get_h();
1382 edit_dimensions(edit, x, y, w, h);
1384 if( edit->track->show_titles() )
1385 y += mwindow->theme->get_image("title_bg_data")->get_h();
1387 if(side == EDIT_OUT)
1394 void TrackCanvas::get_transition_coords(Edit *edit,
1395 int64_t &x, int64_t &y, int64_t &w, int64_t &h)
1397 int transition_w = 30, transition_h = 30;
1398 int has_titles = edit->track->show_titles();
1399 int has_assets = edit->track->show_assets();
1400 double title_bg_h = mwindow->theme->get_image("title_bg_data")->get_h();
1401 double asset_h = resource_h();
1402 double ys = has_assets ? asset_h : has_titles ? title_bg_h : 0;
1403 double dy = has_titles ?
1404 ( has_assets ? title_bg_h + asset_h/2 : title_bg_h/2 ) :
1405 ( has_assets ? asset_h/2 : 0) ;
1406 double title_h = mwindow->theme->title_h;
1407 if( dy < title_h / 2 ) { ys = title_h; dy = ys / 2; }
1410 x -= transition_w / 2;
1411 y -= transition_h / 2;
1416 void TrackCanvas::draw_highlighting()
1421 switch(mwindow->session->current_operation)
1423 case DRAG_ATRANSITION:
1424 case DRAG_VTRANSITION:
1425 //printf("TrackCanvas::draw_highlighting 1 %p %p\n",
1426 // mwindow->session->track_highlighted, mwindow->session->edit_highlighted);
1427 if(mwindow->session->edit_highlighted) {
1428 if((mwindow->session->current_operation == DRAG_ATRANSITION &&
1429 mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
1430 (mwindow->session->current_operation == DRAG_VTRANSITION &&
1431 mwindow->session->track_highlighted->data_type == TRACK_VIDEO)) {
1432 edit_dimensions(mwindow->session->edit_highlighted,
1434 if(MWindowGUI::visible(x, x + w, 0, get_w()) &&
1435 MWindowGUI::visible(y, y + h, 0, get_h())) {
1437 get_transition_coords(mwindow->session->edit_highlighted,
1444 // Dragging a new effect from the Resource window
1447 if(mwindow->session->track_highlighted &&
1448 ((mwindow->session->current_operation == DRAG_AEFFECT &&
1449 mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
1450 (mwindow->session->current_operation == DRAG_VEFFECT &&
1451 mwindow->session->track_highlighted->data_type == TRACK_VIDEO))) {
1452 // Put it before another plugin
1453 if(mwindow->session->plugin_highlighted) {
1454 plugin_dimensions(mwindow->session->plugin_highlighted,
1456 //printf("TrackCanvas::draw_highlighting 1 %d %d\n", x, w);
1458 // Put it after a plugin set
1459 else if( mwindow->session->pluginset_highlighted &&
1460 mwindow->session->pluginset_highlighted->last ) {
1461 plugin_dimensions((Plugin*)mwindow->session->pluginset_highlighted->last,
1463 //printf("TrackCanvas::draw_highlighting 1 %d %d\n", x, w);
1464 int64_t track_x, track_y, track_w, track_h;
1465 track_dimensions(mwindow->session->track_highlighted,
1466 track_x, track_y, track_w, track_h);
1470 mwindow->session->track_highlighted->get_length() *
1471 mwindow->edl->session->sample_rate /
1472 mwindow->edl->local_session->zoom_sample -
1473 mwindow->edl->local_session->view_start[pane->number]) -
1475 //printf("TrackCanvas::draw_highlighting 2 %d\n", w);
1476 if(w <= 0) w = track_w;
1479 track_dimensions(mwindow->session->track_highlighted,
1482 //printf("TrackCanvas::draw_highlighting 1 %d %d %d %d\n", x, y, w, h);
1483 // Put it in a new plugin set determined by the selected range
1484 if(mwindow->edl->local_session->get_selectionend() >
1485 mwindow->edl->local_session->get_selectionstart()) {
1486 x = Units::to_int64(mwindow->edl->local_session->get_selectionstart() *
1487 mwindow->edl->session->sample_rate /
1488 mwindow->edl->local_session->zoom_sample -
1489 mwindow->edl->local_session->view_start[pane->number]);
1490 w = Units::to_int64((mwindow->edl->local_session->get_selectionend() -
1491 mwindow->edl->local_session->get_selectionstart()) *
1492 mwindow->edl->session->sample_rate /
1493 mwindow->edl->local_session->zoom_sample);
1495 // Put it in a new plugin set determined by an edit boundary
1496 else if(mwindow->session->edit_highlighted) {
1497 int64_t temp_y, temp_h;
1498 edit_dimensions(mwindow->session->edit_highlighted,
1499 x, temp_y, w, temp_h);
1501 // Put it at the beginning of the track in a new plugin set
1504 if( MWindowGUI::visible(x, x + w, 0, get_w()) &&
1505 MWindowGUI::visible(y, y + h, 0, get_h()) ) {
1506 //printf("TrackCanvas::draw_highlighting 1\n");
1513 if(mwindow->session->track_highlighted) {
1514 // track_dimensions(mwindow->session->track_highlighted, x, y, w, h);
1516 // if(MWindowGUI::visible(y, y + h, 0, get_h()))
1518 draw_paste_destination();
1524 if(mwindow->session->track_highlighted) {
1525 // track_dimensions(mwindow->session->track_highlighted, x, y, w, h);
1527 // if(MWindowGUI::visible(y, y + h, 0, get_h())) {
1528 draw_paste_destination();
1533 // Dragging an effect from the timeline
1534 case DRAG_AEFFECT_COPY:
1535 case DRAG_VEFFECT_COPY:
1536 if( (mwindow->session->plugin_highlighted || mwindow->session->track_highlighted) &&
1537 ((mwindow->session->current_operation == DRAG_AEFFECT_COPY &&
1538 mwindow->session->track_highlighted->data_type == TRACK_AUDIO) ||
1539 (mwindow->session->current_operation == DRAG_VEFFECT_COPY &&
1540 mwindow->session->track_highlighted->data_type == TRACK_VIDEO))) {
1542 int64_t plugin_position = -1;
1543 Plugin *drag_plugin = mwindow->session->drag_plugin;
1544 PluginSet *hi_plugin_set = mwindow->session->pluginset_highlighted;
1545 Track *hi_track = mwindow->session->track_highlighted;
1546 Edit *hi_edit = mwindow->session->edit_highlighted;
1547 // Put it into a silence zone
1548 if( hi_plugin_set && hi_plugin_set->last &&
1549 hi_plugin_set->track == drag_plugin->track ) {
1550 plugin_dimensions((Plugin *)hi_plugin_set->last, x, y, w, h);
1551 plugin_position = drop_plugin_position(hi_plugin_set, drag_plugin);
1552 hi_track = drag_plugin->track;
1554 else if( hi_track ) {
1555 // Put it in a new plugin set determined by an edit boundary, or at the start of the track
1556 track_dimensions(hi_track, x, y, w, h);
1557 plugin_position = hi_edit ? hi_edit->startproject : 0;
1560 if( plugin_position < 0 ) break;
1562 // Calculate length of plugin based on data type of track and units
1563 double zoom_scale = (double)mwindow->edl->session->sample_rate /
1564 mwindow->edl->local_session->zoom_sample;
1565 x = Units::round(hi_track->from_units(plugin_position) * zoom_scale) -
1566 mwindow->edl->local_session->view_start[pane->number];
1567 w = Units::round(hi_track->from_units(drag_plugin->length) * zoom_scale);
1569 if( MWindowGUI::visible(x, x + w, 0, get_w()) &&
1570 MWindowGUI::visible(y, y + h, 0, get_h()) ) {
1576 case DRAG_PLUGINKEY:
1577 if(mwindow->session->plugin_highlighted &&
1578 mwindow->session->current_operation == DRAG_PLUGINKEY)
1580 // Just highlight the plugin
1581 plugin_dimensions(mwindow->session->plugin_highlighted, x, y, w, h);
1583 if(MWindowGUI::visible(x, x + w, 0, get_w()) &&
1584 MWindowGUI::visible(y, y + h, 0, get_h()))
1596 draw_highlight_rectangle(x, y, w, h);
1600 void TrackCanvas::draw_plugins()
1602 char string[BCTEXTLEN];
1604 int current_show = 0;
1605 int current_preset = 0;
1607 for(int i = 0; i < plugin_on_toggles.total; i++)
1608 plugin_on_toggles.values[i]->in_use = 0;
1609 for(int i = 0; i < plugin_show_toggles.total; i++)
1610 plugin_show_toggles.values[i]->in_use = 0;
1611 for(int i = 0; i < preset_edit_buttons.total; i++)
1612 plugin_show_toggles.values[i]->in_use = 0;
1615 for(Track *track = mwindow->edl->tracks->first;
1617 track = track->next)
1619 if(track->expand_view)
1621 for(int i = 0; i < track->plugin_set.total; i++)
1623 PluginSet *pluginset = track->plugin_set.values[i];
1625 for(Plugin *plugin = (Plugin*)pluginset->first; plugin; plugin = (Plugin*)plugin->next)
1627 int64_t total_x, y, total_w, h;
1628 plugin_dimensions(plugin, total_x, y, total_w, h);
1630 if(MWindowGUI::visible(total_x, total_x + total_w, 0, get_w()) &&
1631 MWindowGUI::visible(y, y + h, 0, get_h()) &&
1632 plugin->plugin_type != PLUGIN_NONE)
1634 int x = total_x, w = total_w, left_margin = 5;
1635 int right_margin = 5;
1641 if(w + x > get_w()) w -= (w + x) - get_w();
1648 mwindow->theme->get_image("plugin_bg_data"),
1650 set_color(mwindow->theme->title_color);
1651 set_font(mwindow->theme->title_font);
1652 plugin->calculate_title(string, 0);
1654 // Truncate string to int64_test visible in background
1655 int len = strlen(string), j;
1656 for(j = len; j >= 0; j--)
1658 if(left_margin + get_text_width(mwindow->theme->title_font, string) > w)
1666 // Justify the text on the left boundary of the edit if it is visible.
1667 // Otherwise justify it on the left side of the screen.
1668 int64_t text_x = total_x + left_margin;
1669 int64_t text_w = get_text_width(mwindow->theme->title_font, string, strlen(string));
1670 text_x = MAX(left_margin, text_x);
1672 y + get_text_ascent(mwindow->theme->title_font) + 2,
1676 int64_t min_x = total_x + text_w;
1679 // Update plugin toggles
1680 int toggle_x = total_x + total_w;
1682 toggle_x = MIN(get_w() - right_margin, toggle_x);
1685 toggle_x -= PluginOn::calculate_w(mwindow) + 10;
1686 if(toggle_x > min_x)
1688 if(current_on >= plugin_on_toggles.total)
1690 PluginOn *plugin_on = new PluginOn(mwindow, toggle_x, toggle_y, plugin);
1691 add_subwindow(plugin_on);
1692 plugin_on_toggles.append(plugin_on);
1696 plugin_on_toggles.values[current_on]->update(toggle_x, toggle_y, plugin);
1701 // Toggles for standalone plugins only
1702 if(plugin->plugin_type == PLUGIN_STANDALONE)
1705 toggle_x -= PluginShow::calculate_w(mwindow) + 10;
1706 if(toggle_x > min_x)
1708 if(current_show >= plugin_show_toggles.total)
1710 PluginShow *plugin_show = new PluginShow(mwindow, toggle_x, toggle_y, plugin);
1711 add_subwindow(plugin_show);
1712 plugin_show_toggles.append(plugin_show);
1716 plugin_show_toggles.values[current_show]->update(toggle_x, toggle_y, plugin);
1720 toggle_x -= PluginPresetEdit::calculate_w(mwindow) + 10;
1721 if(toggle_x > min_x)
1723 if(current_preset >= preset_edit_buttons.total)
1725 PluginPresetEdit *preset_edit = new PluginPresetEdit(mwindow, toggle_x, toggle_y, plugin);
1726 add_subwindow(preset_edit);
1727 preset_edit_buttons.append(preset_edit);
1731 preset_edit_buttons.values[current_preset]->update(toggle_x, toggle_y, plugin);
1742 // Remove unused toggles
1744 while(current_preset < preset_edit_buttons.total)
1746 preset_edit_buttons.remove_object_number(current_preset);
1748 while(current_show < plugin_show_toggles.total)
1750 plugin_show_toggles.remove_object_number(current_show);
1753 while(current_on < plugin_on_toggles.total)
1755 plugin_on_toggles.remove_object_number(current_on);
1759 void TrackCanvas::refresh_plugintoggles()
1761 for(int i = 0; i < plugin_on_toggles.total; i++)
1763 PluginOn *on = plugin_on_toggles.values[i];
1764 on->reposition_window(on->get_x(), on->get_y());
1766 for(int i = 0; i < plugin_show_toggles.total; i++)
1768 PluginShow *show = plugin_show_toggles.values[i];
1769 show->reposition_window(show->get_x(), show->get_y());
1771 for(int i = 0; i < preset_edit_buttons.total; i++)
1773 PluginPresetEdit *preset_edit = preset_edit_buttons.values[i];
1774 preset_edit->reposition_window(preset_edit->get_x(), preset_edit->get_y());
1778 void TrackCanvas::draw_hard_edges()
1782 for(Track *track = mwindow->edl->tracks->first; track; track = track->next) {
1783 for(Edit *edit = track->edits->first; edit; edit = edit->next) {
1784 if( !edit->hard_left && !edit->hard_right ) continue;
1785 edit_dimensions(edit, x, y, w, h);
1789 if( track->show_titles() )
1790 y1 += mwindow->theme->get_image("title_bg_data")->get_h();
1791 if( track->show_assets() )
1794 y1 += mwindow->theme->title_h;
1795 if( edit->hard_left ) {
1796 ArrayList<int> xpt, ypt;
1797 xpt.append(x); ypt.append(y1);
1798 xpt.append(x+HANDLE_W); ypt.append(y1);
1799 xpt.append(x); ypt.append(y1-HANDLE_H);
1800 fill_polygon(&xpt, &ypt);
1802 if( edit->hard_right ) {
1803 ArrayList<int> xpt, ypt; int x1 = x+w-1;
1804 xpt.append(x1); ypt.append(y1);
1805 xpt.append(x1-HANDLE_W); ypt.append(y1);
1806 xpt.append(x1); ypt.append(y1-HANDLE_H);
1807 fill_polygon(&xpt, &ypt);
1813 void TrackCanvas::draw_inout_points()
1818 void TrackCanvas::draw_drag_handle()
1820 if(mwindow->session->current_operation == DRAG_EDITHANDLE2 ||
1821 mwindow->session->current_operation == DRAG_PLUGINHANDLE2)
1823 //printf("TrackCanvas::draw_drag_handle 1 %ld %ld\n", mwindow->session->drag_sample, mwindow->edl->local_session->view_start);
1824 int64_t pixel1 = Units::round(mwindow->session->drag_position *
1825 mwindow->edl->session->sample_rate /
1826 mwindow->edl->local_session->zoom_sample -
1827 mwindow->edl->local_session->view_start[pane->number]);
1828 //printf("TrackCanvas::draw_drag_handle 2 %d %jd\n", pane->number, pixel1);
1829 set_color(!snapped ? GREEN : (snapped=0, YELLOW));
1831 //printf("TrackCanvas::draw_drag_handle 3\n");
1832 draw_line(pixel1, 0, pixel1, get_h());
1834 //printf("TrackCanvas::draw_drag_handle 4\n");
1839 void TrackCanvas::draw_transitions()
1843 for(Track *track = mwindow->edl->tracks->first; track; track = track->next) {
1844 if( !track->show_transitions() ) continue;
1846 for(Edit *edit = track->edits->first; edit; edit = edit->next) {
1847 if(!edit->transition) continue;
1848 edit_dimensions(edit, x, y, w, h);
1849 int strip_x = x, edit_y = y;
1850 get_transition_coords(edit, x, y, w, h);
1851 int strip_y = y - mwindow->theme->get_image("plugin_bg_data")->get_h();
1852 if( track->show_assets() && track->show_titles() )
1853 edit_y += mwindow->theme->get_image("title_bg_data")->get_h();
1854 if( strip_y < edit_y ) strip_y = edit_y;
1856 int strip_w = Units::round(edit->track->from_units(edit->transition->length) *
1857 mwindow->edl->session->sample_rate / mwindow->edl->local_session->zoom_sample);
1858 if( MWindowGUI::visible(x, x + w, 0, get_w()) &&
1859 MWindowGUI::visible(y, y + h, 0, get_h()) ) {
1860 PluginServer *server = mwindow->scan_plugindb(edit->transition->title,
1862 if( !server ) continue;
1863 VFrame *picon = server->get_picon();
1864 if( !picon ) continue;
1865 int picon_w = picon->get_w(), picon_h = picon->get_h();
1866 int track_h = edit->track->vertical_span(mwindow->theme);
1867 if( picon_h > track_h ) picon_h = track_h;
1868 draw_vframe(picon, x, y, w, h, 0, 0, picon_w, picon_h);
1870 if(MWindowGUI::visible(strip_x, strip_x + strip_w, 0, get_w()) &&
1871 MWindowGUI::visible(strip_y, strip_y + h, 0, get_h())) {
1872 int x = strip_x, w = strip_w;
1873 if( x < 0 ) { w -= -x; x = 0; }
1874 if( w + x > get_w() ) w -= (w + x) - get_w();
1876 draw_3segmenth( x, strip_y, w, strip_x, strip_w,
1877 mwindow->theme->get_image("plugin_bg_data"), 0);
1883 void TrackCanvas::draw_loop_points()
1885 //printf("TrackCanvas::draw_loop_points 1\n");
1886 if(mwindow->edl->local_session->loop_playback)
1888 //printf("TrackCanvas::draw_loop_points 2\n");
1889 int64_t x = Units::round(mwindow->edl->local_session->loop_start *
1890 mwindow->edl->session->sample_rate /
1891 mwindow->edl->local_session->zoom_sample -
1892 mwindow->edl->local_session->view_start[pane->number]);
1893 //printf("TrackCanvas::draw_loop_points 3\n");
1895 if(MWindowGUI::visible(x, x + 1, 0, get_w()))
1898 draw_line(x, 0, x, get_h());
1900 //printf("TrackCanvas::draw_loop_points 4\n");
1902 x = Units::round(mwindow->edl->local_session->loop_end *
1903 mwindow->edl->session->sample_rate /
1904 mwindow->edl->local_session->zoom_sample -
1905 mwindow->edl->local_session->view_start[pane->number]);
1906 //printf("TrackCanvas::draw_loop_points 5\n");
1908 if(MWindowGUI::visible(x, x + 1, 0, get_w()))
1911 draw_line(x, 0, x, get_h());
1913 //printf("TrackCanvas::draw_loop_points 6\n");
1915 //printf("TrackCanvas::draw_loop_points 7\n");
1918 void TrackCanvas::draw_brender_range()
1920 if( !mwindow->preferences->use_brender || !mwindow->brender_active ) return;
1921 if( mwindow->edl->session->brender_start >= mwindow->edl->session->brender_end ) return;
1922 if( mwindow->edl->session->brender_end > 0 )
1924 int64_t x1 = Units::round(mwindow->edl->session->brender_start *
1925 mwindow->edl->session->sample_rate /
1926 mwindow->edl->local_session->zoom_sample -
1927 mwindow->edl->local_session->view_start[pane->number]);
1928 if(MWindowGUI::visible(x1, x1 + 1, 0, get_w()))
1931 draw_line(x1, 0, x1, get_h());
1933 int64_t x2 = Units::round(mwindow->edl->session->brender_end *
1934 mwindow->edl->session->sample_rate /
1935 mwindow->edl->local_session->zoom_sample -
1936 mwindow->edl->local_session->view_start[pane->number]);
1938 if(MWindowGUI::visible(x2, x2 + 1, 0, get_w()))
1941 draw_line(x2, 0, x2, get_h());
1946 // The operations which correspond to each automation type
1947 int TrackCanvas::auto_operations[AUTOMATION_TOTAL] =
1963 // The buttonpress operations, so nothing changes unless the mouse moves
1964 // a certain amount. This allows the keyframe to be used to position the
1965 // insertion point without moving itself.
1966 static int pre_auto_operations[AUTOMATION_TOTAL] =
1983 int TrackCanvas::do_keyframes(int cursor_x,
1991 // Note: button 3 (right mouse button) is not eaten to allow
1992 // track context menu to appear
1994 EDLSession *session = mwindow->edl->session;
1998 static BC_Pixmap *auto_pixmaps[AUTOMATION_TOTAL] =
2000 0, 0, 0, 0, 0, 0, 0, 0,
2002 modekeyframe_pixmap,
2003 maskkeyframe_pixmap,
2008 for(Track *track = mwindow->edl->tracks->first;
2010 track = track->next) {
2011 Auto *auto_keyframe = 0;
2012 Automation *automation = track->automation;
2015 // Handle keyframes in reverse drawing order if a button press
2017 int end = AUTOMATION_TOTAL;
2021 start = AUTOMATION_TOTAL - 1;
2025 for(int i = start; i != end && !result; i += step)
2027 // Event not trapped and automation visible
2028 Autos *autos = automation->autos[i];
2029 if(!result && session->auto_conf->autos[i] && autos) {
2031 case AUTOMATION_MODE:
2032 case AUTOMATION_PAN:
2033 case AUTOMATION_MASK:
2034 result = do_autos(track, automation->autos[i],
2035 cursor_x, cursor_y, draw,
2036 buttonpress, auto_pixmaps[i],
2037 auto_keyframe, rerender);
2041 switch(autos->get_type()) {
2042 case Autos::AUTOMATION_TYPE_FLOAT: {
2043 Automation automation(0, track);
2044 int grouptype = automation.autogrouptype(i, track);
2045 if( buttonpress && i == AUTOMATION_SPEED ) {
2046 mwindow->speed_before();
2049 if(draw) // Do dropshadow
2050 result = do_float_autos(track, autos,
2051 cursor_x, cursor_y, draw,
2052 buttonpress, 1, 1, MDGREY,
2053 auto_keyframe, grouptype);
2054 result = do_float_autos(track, autos,
2055 cursor_x, cursor_y, draw, buttonpress,
2056 0, 0, GWindowGUI::auto_colors[i],
2057 auto_keyframe, grouptype);
2059 if( !result && buttonpress && i == AUTOMATION_SPEED )
2060 mwindow->speed_after(-1);
2061 int current_grouptype = mwindow->edl->local_session->zoombar_showautotype;
2062 if( result && buttonpress && grouptype != current_grouptype ) {
2063 mwindow->edl->local_session->zoombar_showautotype = grouptype;
2064 mwindow->gui->zoombar->update_autozoom();
2068 case Autos::AUTOMATION_TYPE_INT: {
2069 if(draw) // Do dropshadow
2070 result = do_int_autos(track, autos,
2071 cursor_x, cursor_y, draw,
2072 buttonpress, 1, 1, MDGREY,
2074 result = do_int_autos(track, autos,
2075 cursor_x, cursor_y, draw, buttonpress,
2076 0, 0, GWindowGUI::auto_colors[i],
2085 if(mwindow->session->current_operation == auto_operations[i])
2088 // printf("TrackCanvas::do_keyframes %d %d %d\n",
2090 // mwindow->session->current_operation,
2091 // auto_operations[i]);
2094 if (buttonpress == 2 && auto_keyframe )
2096 double position = track->from_units(auto_keyframe->position);
2097 mwindow->edl->local_session->set_selectionstart(position);
2098 mwindow->edl->local_session->set_selectionend(position);
2100 if (buttonpress != 3)
2102 if(i == AUTOMATION_FADE || i == AUTOMATION_SPEED)
2103 fill_ganged_autos(get_double_click(), 0, track,
2104 (FloatAuto*)mwindow->session->drag_auto);
2105 mwindow->session->current_operation = pre_auto_operations[i];
2106 update_drag_caption();
2109 else if( auto_keyframe )
2111 gui->keyframe_menu->update(automation,
2114 gui->keyframe_menu->activate_menu();
2115 rerender = 1; // the position changes
2119 gui->keyframe_hide->update(autos);
2120 gui->keyframe_hide->activate_menu();
2121 rerender = 1; // the position changes
2123 if(buttonpress == 1 && ctrl_down() &&
2124 AUTOMATION_TYPE_FLOAT == autos->get_type())
2125 rerender = 1; // special case: curve mode changed
2131 if(!result && session->auto_conf->plugins) {
2134 result = do_plugin_autos(track, cursor_x, cursor_y,
2135 draw, buttonpress, plugin, keyframe);
2136 if(result && mwindow->session->current_operation == DRAG_PLUGINKEY) {
2139 if(result && (buttonpress == 1)) {
2140 mwindow->session->current_operation = DRAG_PLUGINKEY_PRE;
2141 update_drag_caption();
2144 else if (result && (buttonpress == 3)) {
2145 gui->keyframe_menu->update(plugin, keyframe);
2146 gui->keyframe_menu->activate_menu();
2147 rerender = 1; // the position changes
2152 // Final pass to trap event
2153 for(int i = 0; i < AUTOMATION_TOTAL; i++) {
2154 if(mwindow->session->current_operation == pre_auto_operations[i] ||
2155 mwindow->session->current_operation == auto_operations[i]) {
2161 if(mwindow->session->current_operation == DRAG_PLUGINKEY ||
2162 mwindow->session->current_operation == DRAG_PLUGINKEY_PRE) {
2168 new_cursor = UPRIGHT_ARROW_CURSOR;
2175 void TrackCanvas::draw_keyframe_reticle()
2177 int keyframe_hairline = mwindow->preferences->keyframe_reticle;
2178 if( keyframe_hairline == HAIRLINE_NEVER ) return;
2180 int current_op = mwindow->session->current_operation, dragging = 0;
2181 for( int i=0; !dragging && i<AUTOMATION_TOTAL; ++i )
2182 if( current_op == auto_operations[i] ) dragging = 1;
2183 if( dragging && !mwindow->session->drag_auto ) dragging = 0;
2185 int autoidx = dragging && keyframe_hairline != HAIRLINE_ALWAYS ?
2186 mwindow->session->drag_auto->autos->autoidx : -1;
2188 if( get_buttonpress() == 1 && dragging &&
2189 keyframe_hairline == HAIRLINE_DRAGGING ) {
2190 draw_hairline(mwindow->session->drag_auto, RED, 1);
2194 if( keyframe_hairline == HAIRLINE_ALWAYS || ( get_buttonpress() == 2 &&
2195 keyframe_hairline == HAIRLINE_DRAGGING && dragging ) ) {
2196 int show = dragging || keyframe_hairline == HAIRLINE_ALWAYS ? 1 : 0;
2197 for( Track *track = mwindow->edl->tracks->first; track; track=track->next ) {
2198 Automation *automation = track->automation;
2199 for( int i=0; i<AUTOMATION_TOTAL; ++i ) {
2200 if( !mwindow->edl->session->auto_conf->autos[i] ) continue;
2201 // automation visible
2202 Autos *autos = automation->autos[i];
2203 if( !autos ) continue;
2204 if( autoidx >= 0 && autos->autoidx != autoidx ) continue;
2205 for( Auto *auto_keyframe=autos->first; auto_keyframe;
2206 auto_keyframe = auto_keyframe->next ) {
2207 draw_hairline(auto_keyframe, BLUE, show);
2213 draw_hairline(mwindow->session->drag_auto, RED, 1);
2217 void TrackCanvas::draw_auto(Auto *current,
2225 x1 = x - HANDLE_W / 2;
2226 x2 = x + HANDLE_W / 2;
2227 y1 = center_pixel + y - HANDLE_W / 2;
2228 y2 = center_pixel + y + HANDLE_W / 2;
2230 if(y1 < center_pixel + -zoom_track / 2) y1 = center_pixel + -zoom_track / 2;
2231 if(y2 > center_pixel + zoom_track / 2) y2 = center_pixel + zoom_track / 2;
2233 draw_box(x1, y1, x2 - x1, y2 - y1);
2237 // This draws lines for bezier in & out controls
2238 void TrackCanvas::draw_cropped_line(int x1,
2247 // Don't care about x since it is clipped by the window.
2248 // Put y coords in ascending order
2250 y2 ^= y1; y1 ^= y2; y2 ^= y1;
2251 x2 ^= x1; x1 ^= x2; x2 ^= x1;
2256 double slope = (double)(x2 - x1) / (y2 - y1);
2257 //printf("TrackCanvas::draw_cropped_line %d %d %d %d %d\n", __LINE__, x1, y1, x2, y2);
2259 x1 = (int)(x1 + (min_y - y1) * slope);
2262 else if(y1 >= max_y) {
2263 x1 = (int)(x1 + (max_y - 1 - y1) * slope);
2268 x2 = (int)(x2 + (max_y - 1 - y2) * slope);
2271 else if(y2 < min_y) {
2272 x2 = (int)(x2 + (min_y - y2) * slope);
2277 //printf("TrackCanvas::draw_cropped_line %d %d %d %d %d\n", __LINE__, x1, y1, x2, y2);
2278 if( y1 >= min_y && y1 < max_y &&
2279 y2 >= min_y && y2 < max_y )
2280 draw_line(x1, y1, x2, y2);
2284 void TrackCanvas::draw_floatauto(FloatAuto *current,
2295 int x1 = x - HANDLE_W / 2; // Center
2296 int x2 = x + HANDLE_W / 2;
2297 int y1 = center_pixel + y - HANDLE_H / 2;
2298 int y2 = center_pixel + y + HANDLE_H / 2;
2299 int ymin = center_pixel - zoom_track / 2;
2300 int ymax = center_pixel + zoom_track / 2;
2301 CLAMP(y1, ymin, ymax);
2302 CLAMP(y2, ymin, ymax);
2307 draw_box(x1 + 1, y1 + 1, x2 - x1, y2 - y1);
2309 draw_box(x1, y1, x2 - x1, y2 - y1);
2312 // show bezier control points (only) if this
2313 // floatauto doesn't adjust it's tangents automatically
2314 if(current->curve_mode != FloatAuto::FREE &&
2315 current->curve_mode != FloatAuto::TFREE)
2319 draw_floatauto_ctrlpoint(x, y, in_x, in_y, center_pixel, zoom_track, color);
2321 draw_floatauto_ctrlpoint(x, y, out_x, out_y, center_pixel, zoom_track, color);
2324 inline int quantize(float f) { return (int)floor(f + 0.5); }
2326 inline void TrackCanvas::draw_floatauto_ctrlpoint(
2327 int x, int y, int cp_x, int cp_y, int center_pixel,
2328 int zoom_track, int color)
2329 // draw the tangent and a handle for given bézier ctrl point
2331 bool handle_visible = (abs(cp_y) <= zoom_track / 2);
2333 float slope = (float)(cp_y - y)/(cp_x - x);
2334 CLAMP(cp_y, -zoom_track / 2, zoom_track / 2);
2336 cp_x = x + quantize((cp_y - y) / slope);
2339 cp_y += center_pixel;
2341 // drawing the tangent as a dashed line...
2342 int const dash = HANDLE_W;
2343 int const gap = HANDLE_W / 2;
2344 float sx = 3 * (cp_x - x) / 4.;
2347 // q is the x displacement for a unit line of slope
2348 float q = (sx > 0 ? 1 : -1) / sqrt(1 + slope * slope);
2350 float dist = 1/q * sx;
2356 float sy = slope * sx, ey = slope * ex;
2357 draw_line(quantize(sx + x), quantize(sy + y), quantize(ex + x), quantize(ey + y));
2364 int r = HANDLE_W / 2;
2365 int cp_x1 = cp_x - r;
2366 int cp_y1 = cp_y - r;
2368 draw_disc(cp_x1, cp_y1, 2 * r, 2 * r);
2370 draw_circle(cp_x1, cp_y1, 2 * r, 2 * r);
2375 int TrackCanvas::test_auto(Auto *current,
2376 int x, int y, int center_pixel, int zoom_track,
2377 int cursor_x, int cursor_y, int buttonpress)
2382 x1 = x - HANDLE_W / 2;
2383 x2 = x + HANDLE_W / 2;
2384 y1 = center_pixel + y - HANDLE_H / 2;
2385 y2 = center_pixel + y + HANDLE_H / 2;
2386 int ymin = center_pixel - zoom_track / 2;
2387 int ymax = center_pixel + zoom_track / 2;
2388 CLAMP(y1, ymin, ymax);
2389 CLAMP(y2, ymin, ymax);
2391 if(cursor_x >= x1 && cursor_x < x2 && cursor_y >= y1 && cursor_y < y2)
2393 if(buttonpress && buttonpress != 3)
2395 mwindow->session->drag_auto = current;
2396 mwindow->session->drag_start_percentage = (float)((IntAuto*)current)->value;
2397 // Toggle Autos don't respond to vertical zoom, they always show up
2398 // with "on" == 100% == line on top
2399 mwindow->session->drag_start_position = current->position;
2400 mwindow->session->drag_origin_x = cursor_x;
2401 mwindow->session->drag_origin_y = cursor_y;
2406 if(buttonpress && buttonpress != 3 && result)
2408 //printf("TrackCanvas::test_auto %d\n", __LINE__);
2409 mwindow->undo->update_undo_before();
2415 // some Helpers for test_floatauto(..)
2416 // and for dragging the tangents/ctrl points
2417 inline float test_curve_line( int x0, int y0, int ctrl_x, int ctrl_y,
2418 float cursor_x, float cursor_y)
2420 // Control point switched off?
2421 if( x0 == ctrl_x ) return 0.0;
2422 double x1 = ctrl_x-x0, y1 = ctrl_y-y0;
2423 double x = cursor_x-x0, y = cursor_y-y0;
2424 // wrong side of ctrl handle
2425 if( x*x1 < 0 ) return 0.0;
2426 // outside handle radius
2427 if( (x*x + y*y) > (x1*x1 + y1*y1) ) return 0;
2428 double xx1 = x1*x1, yy1 = y1*y1;
2429 double xx = x*x, yy = y*y;
2430 // distance squared from cursor to cursor projected to line from ctrl to handle
2431 // along a line perpendicular to line from ctrl to handle (closest approach)
2432 // (x**2*y1**2 - 2*x*x1*y*y1 + x1**2*y**2)/(x1**2 + y1**2)
2433 double dist2 = (xx*yy1 - 2*x*x1*y*y1 + xx1*yy)/(xx1 + yy1);
2434 return dist2 < (HANDLE_W*HANDLE_W)/4. ? x/x1 : 0.;
2439 float levered_position(float position, float ref_pos)
2441 if( 1e-6 > fabs(ref_pos) || isnan(ref_pos))
2443 return ref_pos / position;
2447 float TrackCanvas::value_to_percentage(float auto_value, int autogrouptype)
2448 // transforms automation value into current display coords,
2449 // dependant on current automation display range for the given kind of automation
2451 if(!mwindow || !mwindow->edl) return 0;
2452 float automation_min = mwindow->edl->local_session->automation_mins[autogrouptype];
2453 float automation_max = mwindow->edl->local_session->automation_maxs[autogrouptype];
2454 float automation_range = automation_max - automation_min;
2455 if( 0 >= automation_range || isnan(auto_value) || isinf(auto_value) )
2457 return (auto_value - automation_min) / automation_range;
2462 int TrackCanvas::test_floatauto(FloatAuto *current, int x, int y, int in_x,
2463 int in_y, int out_x, int out_y, int center_pixel, int zoom_track,
2464 int cursor_x, int cursor_y, int buttonpress, int autogrouptype)
2468 int x1 = x - HANDLE_W / 2;
2469 int x2 = x + HANDLE_W / 2;
2470 int y1 = center_pixel + y - HANDLE_W / 2;
2471 int y2 = center_pixel + y + HANDLE_W / 2;
2472 int ymin = center_pixel - zoom_track / 2;
2473 int ymax = center_pixel + zoom_track / 2;
2474 CLAMP(y1, ymin, ymax);
2475 CLAMP(y2, ymin, ymax);
2477 int in_x1 = in_x - HANDLE_W / 2;
2478 int in_x2 = in_x + HANDLE_W / 2;
2479 int in_y1 = center_pixel + in_y - HANDLE_W / 2;
2480 int in_y2 = center_pixel + in_y + HANDLE_W / 2;
2481 CLAMP(in_y1, ymin, ymax);
2482 CLAMP(in_y2, ymin, ymax);
2484 int out_x1 = out_x - HANDLE_W / 2;
2485 int out_x2 = out_x + HANDLE_W / 2;
2486 int out_y1 = center_pixel + out_y - HANDLE_W / 2;
2487 int out_y2 = center_pixel + out_y + HANDLE_W / 2;
2488 CLAMP(out_y1, ymin, ymax);
2489 CLAMP(out_y2, ymin, ymax);
2492 //printf("TrackCanvas::test_floatauto %d %d %d %d %d %d\n", cursor_x, cursor_y, x1, x2, y1, y2);
2493 // buttonpress could be the start of a drag operation
2494 #define INIT_DRAG(POS,VAL) \
2495 mwindow->session->drag_auto = current; \
2496 mwindow->session->drag_origin_x = cursor_x; \
2497 mwindow->session->drag_origin_y = cursor_y; \
2498 mwindow->session->drag_start_position = (POS); \
2499 mwindow->session->drag_start_percentage = (VAL);
2501 #define WITHIN(X1,X2,Y1,Y2) (cursor_x >=(X1) && cursor_x <(X2) && cursor_y >=(Y1) && cursor_y <(Y2) )
2504 // without modifier we are manipulating the automation node
2505 // with ALT it's about dragging only the value of the node
2506 // with SHIFT the value snaps to the value of neighbouring nodes
2507 // CTRL indicates we are rather manipulating the tangent(s) of the node
2511 if( WITHIN(x1,x2,y1,y2))
2512 { // cursor hits node
2515 if(buttonpress && (buttonpress != 3))
2517 INIT_DRAG(current->position, value_to_percentage(current->get_value(), autogrouptype))
2518 mwindow->session->drag_handle = 0;
2523 if( WITHIN(x1,x2,y1,y2))
2526 if(buttonpress && (buttonpress != 3))
2528 // could be ctrl-click or ctrl-drag
2529 // click would cycle through tangent modes
2530 ((FloatAuto*)current)->toggle_curve_mode();
2532 // drag will start dragging the tangent, if applicable
2533 INIT_DRAG(current->position, value_to_percentage(current->get_value(), autogrouptype))
2534 mwindow->session->drag_handle = 0;
2538 float lever = 0.0; // we use the tangent as a draggable lever. 1.0 is at the ctrl point
2541 if( in_x != x && current->position > 0 &&
2542 (FloatAuto::FREE == current->curve_mode ||
2543 FloatAuto::TFREE == current->curve_mode))
2544 // act on in control handle only if
2545 // tangent is significant and is editable (not automatically choosen)
2547 lever = test_curve_line(x, y, in_x, in_y, cursor_x, cursor_y-center_pixel);
2548 // either cursor in ctrl-point handle or cursor on tangent line
2549 if( WITHIN(in_x1,in_x2,in_y1,in_y2) || lever > 0.0 ) {
2551 if(buttonpress && (buttonpress != 3)) {
2552 if(lever == 0.0) lever=1.0; // we entered by dragging the handle...
2554 mwindow->session->drag_handle = 1;
2555 float new_invalue = current->get_value() + lever * current->get_control_in_value();
2556 INIT_DRAG(current->position + (int64_t)(lever * current->get_control_in_position()),
2557 value_to_percentage(new_invalue, autogrouptype))
2564 (FloatAuto::FREE == current->curve_mode ||
2565 FloatAuto::TFREE == current->curve_mode))
2566 // act on out control only if tangent is significant and is editable
2568 lever = test_curve_line(x, y, out_x, out_y, cursor_x, cursor_y-center_pixel);
2569 if(WITHIN(out_x1,out_x2,out_y1,out_y2) || lever > 0.0 ) {
2571 if(buttonpress && (buttonpress != 3)) {
2572 if(lever == 0.0) lever=1.0;
2574 mwindow->session->drag_handle = 2;
2575 float new_outvalue = current->get_value() + lever * current->get_control_out_value();
2576 INIT_DRAG(current->position + (int64_t)(lever * current->get_control_out_position()),
2577 value_to_percentage(new_outvalue, autogrouptype))
2581 } // end ctrl_down()
2587 // 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",
2588 // mwindow->session->drag_handle,
2593 if(buttonpress && (buttonpress != 3) && result)
2595 mwindow->undo->update_undo_before();
2602 // Get the float value & y for position x on the canvas
2603 #define X_TO_FLOATLINE(x) \
2604 int64_t position1 = (int64_t)(unit_start + x * zoom_units); \
2605 int64_t position2 = (int64_t)(unit_start + x * zoom_units) + 1; \
2606 /* Call by reference fails for some reason here */ \
2607 float value1 = autos->get_value(position1, PLAY_FORWARD, previous1, next1); \
2608 float value2 = autos->get_value(position2, PLAY_FORWARD, previous1, next1); \
2609 double position = unit_start + x * zoom_units; \
2611 if(position2 > position1) \
2614 (value2 - value1) * \
2615 (position - position1) / \
2616 (position2 - position1); \
2622 AUTOMATIONCLAMPS(value, autogrouptype); \
2623 int y = center_pixel + \
2624 (int)(((value - automation_min) / automation_range - 0.5) * -yscale);
2627 void TrackCanvas::draw_floatline(int center_pixel,
2628 FloatAuto *previous, FloatAuto *next, FloatAutos *autos,
2629 double unit_start, double zoom_units, double yscale,
2630 int x1, int y1, int x2, int y2,
2631 int color, int autogrouptype)
2633 // Solve bezier equation for either every pixel or a certain large number of
2636 // Not using slope intercept
2638 int prev_y = y1 + center_pixel;
2641 // Call by reference fails for some reason here
2642 FloatAuto *previous1 = previous, *next1 = next;
2643 float automation_min = mwindow->edl->local_session->automation_mins[autogrouptype];
2644 float automation_max = mwindow->edl->local_session->automation_maxs[autogrouptype];
2645 float automation_range = automation_max - automation_min;
2647 for(int x = x1; x < x2; x++)
2649 // Interpolate value between frames
2653 y >= center_pixel - yscale / 2 &&
2654 y < center_pixel + yscale / 2 - 1)
2656 // printf("TrackCanvas::draw_floatline y=%d min=%d max=%d\n",
2658 // (int)(center_pixel - yscale / 2),
2659 // (int)(center_pixel + yscale / 2 - 1));
2661 //printf("draw_line(%d,%d, %d,%d)\n", x - 1, prev_y , x, y);
2662 draw_line(x - 1, prev_y , x, y );
2672 int TrackCanvas::test_floatline(int center_pixel,