#include "edlsession.h"
#include "floatauto.h"
#include "floatautos.h"
+#include "gwindowgui.h"
#include "indexstate.h"
#include "intauto.h"
#include "intautos.h"
{
int64_t edit_x, edit_y, edit_w, edit_h;
edit_dimensions(edit, edit_x, edit_y, edit_w, edit_h);
-
- if(cursor_x >= edit_x &&
- cursor_y >= edit_y &&
- cursor_x < edit_x + edit_w &&
- cursor_y < edit_y + edit_h)
- {
+ if( cursor_y < edit_y || cursor_y >= edit_y + edit_h ) continue;
+ if( cursor_x >= edit_x && cursor_x < edit_x + edit_w ) {
*over_edit = edit;
break;
}
+ if( edit != track->edits->last ) continue;
+ if( mwindow->session->current_operation != DRAG_ATRANSITION &&
+ mwindow->session->current_operation != DRAG_VTRANSITION ) continue;
+ if( !edit->silence() ) {
+ // add silence to allow drag transition past last edit
+ // will be deleted by Edits::optimize if not used
+ double length = mwindow->edl->session->default_transition_length;
+ int64_t start = edit->startproject+edit->length;
+ int64_t units = track->to_units(length, 1);
+ track->edits->create_silence(start, start+units);
+ continue;
+ }
+ if( cursor_x >= edit_x ) { *over_edit = edit; break; }
}
for(int i = 0; i < track->plugin_set.total; i++)
}
if( !*over_track )
- *over_track = pane->is_over_patchbay();
+ *over_track = pane->over_patchbay();
return 0;
}
(cursor_y = get_relative_cursor_y()) >= 0 && cursor_y < get_h() )
over_window = 1;
else {
- Track *track = pane->is_over_patchbay();
+ Track *track = pane->over_patchbay();
if( track && mwindow->session->track_highlighted == track )
over_window = 1;
}
}
}
-static int auto_colors[AUTOMATION_TOTAL] =
-{
- BLUE,
- RED,
- GREEN,
- BLUE,
- RED,
- GREEN,
- BLUE,
- WHITE,
- 0,
- 0,
- 0,
- WHITE
-};
-
// The operations which correspond to each automation type
-static int auto_operations[AUTOMATION_TOTAL] =
+int TrackCanvas::auto_operations[AUTOMATION_TOTAL] =
{
DRAG_MUTE,
DRAG_CAMERA_X,
auto_keyframe, grouptype);
result = do_float_autos(track, autos,
- cursor_x, cursor_y, draw,
- buttonpress, 0, 0, auto_colors[i],
+ cursor_x, cursor_y, draw, buttonpress,
+ 0, 0, GWindowGUI::auto_colors[i],
auto_keyframe, grouptype);
break; }
buttonpress, 1, 1, MDGREY,
auto_keyframe);
result = do_int_autos(track, autos,
- cursor_x, cursor_y, draw,
- buttonpress, 0, 0, auto_colors[i],
+ cursor_x, cursor_y, draw, buttonpress,
+ 0, 0, GWindowGUI::auto_colors[i],
auto_keyframe);
break; }
}
{
if (buttonpress != 3)
{
- if(i == AUTOMATION_FADE)
+ if(i == AUTOMATION_FADE || i == AUTOMATION_SPEED)
synchronize_autos(0,
track,
(FloatAuto*)mwindow->session->drag_auto,
gui->keyframe_menu->activate_menu();
rerender = 1; // the position changes
}
+ else if( autos )
+ {
+ gui->keyframe_hide->update(autos);
+ gui->keyframe_hide->activate_menu();
+ rerender = 1; // the position changes
+ }
if(buttonpress == 1 && ctrl_down() &&
AUTOMATION_TYPE_FLOAT == autos->get_type())
rerender = 1; // special case: curve mode changed
return result;
}
+void TrackCanvas::draw_keyframe_reticle()
+{
+ int keyframe_hairline = mwindow->preferences->keyframe_reticle;
+ if( keyframe_hairline == HAIRLINE_NEVER ) return;
+
+ int current_op = mwindow->session->current_operation, dragging = 0;
+ for( int i=0; !dragging && i<AUTOMATION_TOTAL; ++i )
+ if( current_op == auto_operations[i] ) dragging = 1;
+
+ if( keyframe_hairline == HAIRLINE_DRAGGING && dragging ) {
+ if( mwindow->session->drag_auto && get_buttonpress() == 1 ) {
+ draw_hairline(mwindow->session->drag_auto, RED);
+ return;
+ }
+ }
+
+ if( keyframe_hairline == HAIRLINE_ALWAYS || ( get_buttonpress() == 2 &&
+ keyframe_hairline == HAIRLINE_DRAGGING && dragging ) ) {
+ for( Track *track = mwindow->edl->tracks->first; track;
+ track=track->next ) {
+ Automation *automation = track->automation;
+ for( int i=0; i<AUTOMATION_TOTAL; ++i ) {
+ if( !mwindow->edl->session->auto_conf->autos[i] ) continue;
+ // automation visible
+ Autos *autos = automation->autos[i];
+ if( !autos ) continue;
+ for( Auto *auto_keyframe=autos->first; auto_keyframe;
+ auto_keyframe = auto_keyframe->next ) {
+ draw_hairline(auto_keyframe, GREEN);
+ }
+ }
+
+ if( dragging && mwindow->session->drag_auto ) {
+ draw_hairline(mwindow->session->drag_auto, RED);
+ }
+ }
+ }
+}
+
void TrackCanvas::draw_auto(Auto *current,
int x,
int y,
{
if( 1e-6 > fabs(ref_pos) || isnan(ref_pos))
return 0.0;
- else
- return ref_pos / position;
+ return ref_pos / position;
}
float automation_min = mwindow->edl->local_session->automation_mins[autogrouptype];
float automation_max = mwindow->edl->local_session->automation_maxs[autogrouptype];
float automation_range = automation_max - automation_min;
- if(0 == automation_range || isnan(auto_value) || isinf(auto_value))
+ if( 0 >= automation_range || isnan(auto_value) || isinf(auto_value) )
return 0;
- else
- return (auto_value - automation_min) / automation_range;
+ return (auto_value - automation_min) / automation_range;
}
// Not using slope intercept
x1 = MAX(0, x1);
- int prev_y = y1;
+ int prev_y = y1 + center_pixel;
// Call by reference fails for some reason here
// (int)(center_pixel - yscale / 2),
// (int)(center_pixel + yscale / 2 - 1));
+//printf("draw_line(%d,%d, %d,%d)\n", x - 1, prev_y , x, y);
draw_line(x - 1, prev_y , x, y );
}
prev_y = y;
{
Auto *current;
mwindow->undo->update_undo_before();
- current = mwindow->session->drag_auto = autos->insert_auto(position1);
+ double position = autos->track->from_units(position1);
+ position = mwindow->edl->align_to_frame(position, 0);
+ int64_t new_position = autos->track->to_units(position,0);
+ current = mwindow->session->drag_auto = autos->insert_auto(new_position);
((FloatAuto*)current)->set_value(value);
mwindow->session->drag_start_percentage = value_to_percentage(value, autogrouptype);
mwindow->session->drag_start_position = current->position;
void TrackCanvas::synchronize_autos(float change,
- Track *skip,
- FloatAuto *fauto,
- int fill_gangs)
+ Track *skip, FloatAuto *fauto, int fill_gangs)
{
// Handles the special case of modifying a fadeauto
// when there are ganged faders on several tracks
// (skip and fauto may be NULL if fill_gangs==-1)
- if (fill_gangs == 1 && skip->gang)
- {
- for(Track *current = mwindow->edl->tracks->first;
- current;
- current = NEXT)
- {
- if(current->data_type == skip->data_type &&
- current->gang &&
- current->record &&
- current != skip)
- {
- FloatAutos *fade_autos = (FloatAutos*)current->automation->autos[AUTOMATION_FADE];
- double position = skip->from_units(fauto->position);
- FloatAuto *previous = 0, *next = 0;
-
- float init_value = fade_autos->get_value(fauto->position, PLAY_FORWARD, previous, next);
- FloatAuto *keyframe;
- keyframe = (FloatAuto*)fade_autos->get_auto_at_position(position);
- if (!keyframe)
- {
+ if( fill_gangs > 0 && skip->gang ) {
+ double position = skip->from_units(fauto->position);
+ int autoidx = fauto->autos->autoidx;
+
+ for(Track *current = mwindow->edl->tracks->first; current; current = NEXT) {
+ if( (current->data_type == skip->data_type || get_double_click()) &&
+ current->gang && current->record && current != skip ) {
+ int64_t current_position = current->to_units(position, 1);
+ FloatAutos *fade_autos = (FloatAutos*)current->automation->autos[autoidx];
+ float auto_min = mwindow->edl->local_session->automation_mins[fade_autos->autogrouptype];
+ float auto_max = mwindow->edl->local_session->automation_maxs[fade_autos->autogrouptype];
+ FloatAuto *previous = 0, *next = 0;
+ FloatAuto *keyframe = (FloatAuto*)fade_autos->get_auto_at_position(current_position);
+ if( !keyframe ) {
// create keyframe on neighbouring track at the point in time given by fauto
- keyframe = (FloatAuto*)fade_autos->insert_auto(fauto->position);
- keyframe->set_value(init_value + change);
+ float init_value = fade_autos->get_value(current_position, PLAY_FORWARD, previous, next);
+ float new_value = init_value + change;
+ CLAMP(new_value, auto_min, auto_max);
+ keyframe = (FloatAuto*)fade_autos->insert_auto(current_position);
+ keyframe->set_value(new_value);
}
- else
- {
+ else {
// keyframe exists, just change it
- keyframe->adjust_to_new_coordinates(fauto->position, keyframe->get_value() + change);
+ float new_value = keyframe->get_value() + change;
+ CLAMP(new_value, auto_min, auto_max);
+ keyframe->adjust_to_new_coordinates(current_position, new_value);
// need to (re)set the position, as the existing node could be on a "equivalent" position (within half a frame)
}
mwindow->session->drag_auto_gang->append((Auto *)keyframe);
}
}
- } else
-// move the gangs
- if (fill_gangs == 0)
- {
-// Move the gang!
- for (int i = 0; i < mwindow->session->drag_auto_gang->total; i++)
- {
+ }
+ else if( !fill_gangs ) {
+ double position = skip->from_units(fauto->position);
+// Move the gangs
+ for (int i = 0; i < mwindow->session->drag_auto_gang->total; i++) {
FloatAuto *keyframe = (FloatAuto *)mwindow->session->drag_auto_gang->values[i];
-
+ int64_t keyframe_position = keyframe->autos->track->to_units(position, 1);
float new_value = keyframe->get_value() + change;
CLAMP(new_value,
mwindow->edl->local_session->automation_mins[keyframe->autos->autogrouptype],
mwindow->edl->local_session->automation_maxs[keyframe->autos->autogrouptype]);
- keyframe->adjust_to_new_coordinates(fauto->position, new_value);
+ keyframe->adjust_to_new_coordinates(keyframe_position, new_value);
}
}
- else
+ else {
// remove the gangs
- if (fill_gangs == -1)
- {
- for (int i = 0; i < mwindow->session->drag_auto_gang->total; i++)
- {
+ for (int i = 0; i < mwindow->session->drag_auto_gang->total; i++) {
FloatAuto *keyframe = (FloatAuto *)mwindow->session->drag_auto_gang->values[i];
keyframe->autos->remove_nonsequential(
keyframe);
autos->first ? autos->first : autos->default_auto;
double ax = 0, ay = 0, ax2 = 0, ay2 = 0;
- if( first_auto )
+ if( first_auto ) {
calculate_auto_position(&ax, &ay, 0, 0, 0, 0,
first_auto, unit_start, zoom_units, yscale, autogrouptype);
-
+ }
if( current )
current = NEXT;
else {
return result;
}
+int TrackCanvas::draw_hairline(Auto *auto_keyframe, int color)
+{
+ Track *track = auto_keyframe->autos->track;
+ int autogrouptype = auto_keyframe->autos->get_type();
+
+ int center_pixel;
+ double view_start, unit_start;
+ double view_end, unit_end, yscale;
+ double zoom_sample, zoom_units;
+
+ calculate_viewport(track, view_start, unit_start, view_end, unit_end,
+ yscale, center_pixel, zoom_sample, zoom_units);
+
+ double ax = 0, ay = 0;
+ calculate_auto_position(&ax, &ay, 0, 0, 0, 0,
+ auto_keyframe, unit_start, zoom_units, yscale, autogrouptype);
+
+ set_color(color);
+ draw_line(ax, 0, ax, get_h());
+ return 0;
+}
+
void TrackCanvas::draw_overlays()
{
int new_cursor, update_cursor, rerender;
// Playback cursor
draw_playback_cursor();
+ draw_keyframe_reticle();
+
show_window(0);
}
#define UPDATE_DRAG_HEAD(do_clamp) \
- int result = 0; \
+ int result = 0, center_pixel; \
if(!current->autos->track->record) return 0; \
- double view_start; \
- double unit_start; \
- double view_end; \
- double unit_end; \
- double yscale; \
- int center_pixel; \
- double zoom_sample; \
- double zoom_units; \
+ double view_start, unit_start, view_end, unit_end; \
+ double yscale, zoom_sample, zoom_units; \
\
calculate_viewport(current->autos->track, \
- view_start, \
- unit_start, \
- view_end, \
- unit_end, \
- yscale, \
- center_pixel, \
- zoom_sample, \
- zoom_units); \
+ view_start, unit_start, view_end, unit_end, \
+ yscale, center_pixel, zoom_sample, zoom_units); \
\
float percentage = (float)(mwindow->session->drag_origin_y - cursor_y) / \
- yscale + \
- mwindow->session->drag_start_percentage; \
+ yscale + mwindow->session->drag_start_percentage; \
if(do_clamp) CLAMP(percentage, 0, 1); \
\
int64_t position = Units::to_int64(zoom_units * \
(cursor_x - mwindow->session->drag_origin_x) + \
mwindow->session->drag_start_position); \
- \
if((do_clamp) && position < 0) position = 0;
FloatAuto *current = (FloatAuto*)mwindow->session->drag_auto;
UPDATE_DRAG_HEAD(mwindow->session->drag_handle == 0);
- int x = cursor_x - mwindow->session->drag_origin_x; \
- int y = cursor_y - mwindow->session->drag_origin_y; \
-
- float value;
- float old_value;
+ int x = cursor_x - mwindow->session->drag_origin_x;
+ int y = cursor_y - mwindow->session->drag_origin_y;
+ float value, old_value;
+
+ if( mwindow->session->drag_handle == 0 && (ctrl_down() && !shift_down()) ) {
+// not really editing the node, rather start editing the curve
+// tangent is editable and drag movement is significant
+ if( (FloatAuto::FREE == current->curve_mode ||
+ FloatAuto::TFREE==current->curve_mode) &&
+ (fabs(x) > HANDLE_W / 2 || fabs(y) > HANDLE_W / 2))
+ mwindow->session->drag_handle = x < 0 ? 1 : 2;
+ }
- switch(mwindow->session->drag_handle)
- {
-// Center
- case 0:
- if(ctrl_down())
- // not really editing the node, rather start editing the curve
- {
- // tangent is editable and drag movement is significant
- if( (FloatAuto::FREE == current->curve_mode ||
- FloatAuto::TFREE==current->curve_mode) &&
- (fabs(x) > HANDLE_W / 2 || fabs(y) > HANDLE_W / 2))
- mwindow->session->drag_handle = x < 0 ? 1 : 2;
- break;
- }
+ switch(mwindow->session->drag_handle) {
+ case 0: // Center
// Snap to nearby values
- old_value = current->get_value();
- if(shift_down())
- {
- double value1;
- double distance1;
- double value2;
- double distance2;
+ old_value = current->get_value();
+ if(shift_down()) {
+ double value1, value2, distance1, distance2;
- if(current->previous)
- {
- int autogrouptype = current->previous->autos->autogrouptype;
- value = percentage_to_value(percentage, 0, 0, autogrouptype);
- value1 = ((FloatAuto*)current->previous)->get_value();
- distance1 = fabs(value - value1);
- current->set_value(value1);
- }
-
- if(current->next)
- {
- int autogrouptype = current->next->autos->autogrouptype;
- value = percentage_to_value(percentage, 0, 0, autogrouptype);
- value2 = ((FloatAuto*)current->next)->get_value();
- distance2 = fabs(value - value2);
- if(!current->previous || distance2 < distance1)
- {
- current->set_value(value2);
- }
- }
+ if(current->previous) {
+ int autogrouptype = current->previous->autos->autogrouptype;
+ value = percentage_to_value(percentage, 0, 0, autogrouptype);
+ value1 = ((FloatAuto*)current->previous)->get_value();
+ distance1 = fabs(value - value1);
+ current->set_value(value1);
+ }
- if(!current->previous && !current->next)
- {
- current->set_value( ((FloatAutos*)current->autos)->default_);
+ if(current->next) {
+ int autogrouptype = current->next->autos->autogrouptype;
+ value = percentage_to_value(percentage, 0, 0, autogrouptype);
+ value2 = ((FloatAuto*)current->next)->get_value();
+ distance2 = fabs(value - value2);
+ if(!current->previous || distance2 < distance1) {
+ current->set_value(value2);
}
- value = current->get_value();
}
- else
- {
- int autogrouptype = current->autos->autogrouptype;
- value = percentage_to_value(percentage, 0, 0, autogrouptype);
+
+ if(!current->previous && !current->next) {
+ current->set_value( ((FloatAutos*)current->autos)->default_);
}
+ value = current->get_value();
+ }
+ else {
+ int autogrouptype = current->autos->autogrouptype;
+ value = percentage_to_value(percentage, 0, 0, autogrouptype);
+ }
- if(alt_down())
+ if(alt_down() && !shift_down())
// ALT constrains movement: fixed position, only changing the value
- position = mwindow->session->drag_start_position;
+ position = mwindow->session->drag_start_position;
- if(value != old_value || position != current->position)
- {
- result = 1;
- float change = value - old_value;
- current->adjust_to_new_coordinates(position, value);
- synchronize_autos(change, current->autos->track, current, 0);
- show_message(current, 1,", %.2f", current->get_value());
- }
- break;
+ if(value != old_value || position != current->position) {
+ result = 1;
+ float change = value - old_value;
+ current->adjust_to_new_coordinates(position, value);
+ synchronize_autos(change, current->autos->track, current, 0);
+ show_message(current, 1,", %.2f", current->get_value());
+ }
+ break;
// In control
- case 1:
+ case 1: {
+ int autogrouptype = current->autos->autogrouptype;
+ value = percentage_to_value(percentage, 0, current, autogrouptype);
+ if(value != current->get_control_in_value())
{
- int autogrouptype = current->autos->autogrouptype;
- value = percentage_to_value(percentage, 0, current, autogrouptype);
- if(value != current->get_control_in_value())
- {
- result = 1;
- // note: (position,value) need not be at the location of the ctrl point,
- // but could be somewhere in between on the curve (or even outward or
- // on the opposit side). We set the new control point such as
- // to point the curve through (position,value)
- current->set_control_in_value(
- value * levered_position(position - current->position,
- current->get_control_in_position()));
- synchronize_autos(0, current->autos->track, current, 0);
- show_message(current, 1,", %.2f", current->get_control_in_value());
- }
+ result = 1;
+ // note: (position,value) need not be at the location of the ctrl point,
+ // but could be somewhere in between on the curve (or even outward or
+ // on the opposit side). We set the new control point such as
+ // to point the curve through (position,value)
+ current->set_control_in_value(
+ value * levered_position(position - current->position,
+ current->get_control_in_position()));
+ synchronize_autos(0, current->autos->track, current, 0);
+ show_message(current, 1,", %.2f", current->get_control_in_value());
}
- break;
+ break; }
// Out control
- case 2:
- {
- int autogrouptype = current->autos->autogrouptype;
- value = percentage_to_value(percentage, 0, current, autogrouptype);
- if(value != current->get_control_out_value())
- {
- result = 1;
- current->set_control_out_value(
- value * levered_position(position - current->position,
- current->get_control_out_position()));
- synchronize_autos(0, current->autos->track, current, 0);
- show_message(current, 1,", %.2f", current->get_control_out_value());
- }
+ case 2: {
+ int autogrouptype = current->autos->autogrouptype;
+ value = percentage_to_value(percentage, 0, current, autogrouptype);
+ if(value != current->get_control_out_value()) {
+ result = 1;
+ current->set_control_out_value(
+ value * levered_position(position - current->position,
+ current->get_control_out_position()));
+ synchronize_autos(0, current->autos->track, current, 0);
+ show_message(current, 1,", %.2f", current->get_control_out_value());
}
- break;
+ break; }
}
return result;
switch(mwindow->edl->session->editing_mode) {
// Test handles and resource boundaries and highlight a track
case EDITING_ARROW: {
- if( mwindow->edl->session->auto_conf->transitions &&
- do_transitions(cursor_x, cursor_y,
+ if( do_transitions(cursor_x, cursor_y,
1, new_cursor, update_cursor) ) break;
if( do_keyframes(cursor_x, cursor_y,
mwindow->edl->session->sample_rate;
//printf("TrackCanvas::button_press_event %d\n", position);
- if(mwindow->edl->session->auto_conf->transitions &&
- do_transitions(cursor_x, cursor_y,
+ if( do_transitions(cursor_x, cursor_y,
1, new_cursor, update_cursor)) break;
if(do_keyframes(cursor_x, cursor_y,
0, get_buttonpress(), new_cursor,
if( do_tracks(cursor_x, cursor_y, 1) ) break;
// Highlight selection
+ if( get_buttonpress() != LEFT_BUTTON ) break;
rerender = start_selection(position);
mwindow->session->current_operation = SELECT_REGION;
update_cursor = 1;
if( update_overlay ) {
gui->draw_overlays(1);
}
-
- if( update_cursor > 0 ) {
+ if( update_cursor < 0 ) {
+// double_click edit
+ gui->swindow->update_selection();
+ }
+ if( update_cursor ) {
gui->update_timebar(0);
gui->hide_cursor(0);
gui->show_cursor(1);
gui->zoombar->update();
gui->flash_canvas(1);
}
- else if(update_cursor < 0) {
- gui->swindow->update_selection();
- }
}
return result;
}