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 "bcsignals.h"
24 #include "cplayback.h"
27 #include "cwindowgui.h"
29 #include "edlsession.h"
33 #include "labeledit.h"
34 #include "localsession.h"
35 #include "maincursor.h"
39 #include "mwindowgui.h"
41 #include "preferences.h"
42 #include "recordlabel.h"
43 #include "localsession.h"
44 #include "mainsession.h"
47 #include "timelinepane.h"
48 #include "trackcanvas.h"
50 #include "transportque.h"
54 #include "vwindowgui.h"
58 LabelGUI::LabelGUI(MWindow *mwindow, TimeBar *timebar,
60 double position, VFrame **data)
61 : BC_Toggle(translate_pixel(mwindow, pixel), y,
62 data ? data : mwindow->theme->label_toggle, 0)
64 this->mwindow = mwindow;
65 this->timebar = timebar;
68 this->position = position;
74 if( timebar->drag_label == this )
75 timebar->drag_label = 0;
78 int LabelGUI::get_y(MWindow *mwindow, TimeBar *timebar)
80 return timebar->get_h() -
81 mwindow->theme->label_toggle[0]->get_h();
84 int LabelGUI::translate_pixel(MWindow *mwindow, int pixel)
86 int result = pixel - mwindow->theme->label_toggle[0]->get_w() / 2;
90 void LabelGUI::reposition(int flush)
92 reposition_window(translate_pixel(mwindow, pixel),
96 int LabelGUI::button_press_event()
98 int result = test_drag_label(1);
100 if( this->is_event_win() && get_buttonpress() == 3 ) {
103 get_abs_cursor(cur_x, cur_y, 0);
104 timebar->label_edit->start(label, cur_x, cur_y);
108 result = BC_Toggle::button_press_event();
111 set_tooltip(this->label->textstr);
115 int LabelGUI::button_release_event()
117 int ret = BC_Toggle::button_release_event();
122 int LabelGUI::test_drag_label(int press)
124 if( is_event_win() && get_buttonpress() == 1 ) {
125 switch( timebar->current_operation ) {
127 if( press && get_value() ) {
128 timebar->current_operation = TIMEBAR_DRAG_LABEL;
129 timebar->drag_label = this;
130 set_cursor(MOVE_CURSOR, 0, 0);
131 mwindow->undo->update_undo_before(_("drag label"), this);
135 case TIMEBAR_DRAG_LABEL:
137 timebar->current_operation = TIMEBAR_NONE;
138 set_cursor(ARROW_CURSOR, 0, 0);
139 mwindow->undo->update_undo_after(_("drag label"), LOAD_TIMEBAR);
147 int LabelGUI::handle_event()
149 timebar->select_label(position);
154 InPointGUI::InPointGUI(MWindow *mwindow, TimeBar *timebar,
155 int64_t pixel, double position)
156 : LabelGUI(mwindow, timebar,
157 pixel, get_y(mwindow, timebar),
158 position, mwindow->theme->in_point)
160 //printf("InPointGUI::InPointGUI %d %d\n", pixel, get_y(mwindow, timebar));
162 InPointGUI::~InPointGUI()
165 int InPointGUI::get_y(MWindow *mwindow, TimeBar *timebar)
168 result = timebar->get_h() -
169 mwindow->theme->in_point[0]->get_h();
174 OutPointGUI::OutPointGUI(MWindow *mwindow, TimeBar *timebar,
175 int64_t pixel, double position)
176 : LabelGUI(mwindow, timebar,
177 pixel, get_y(mwindow, timebar),
178 position, mwindow->theme->out_point)
180 //printf("OutPointGUI::OutPointGUI %d %d\n", pixel, get_y(mwindow, timebar));
182 OutPointGUI::~OutPointGUI()
185 int OutPointGUI::get_y(MWindow *mwindow, TimeBar *timebar)
187 return timebar->get_h() -
188 mwindow->theme->out_point[0]->get_h();
192 PresentationGUI::PresentationGUI(MWindow *mwindow, TimeBar *timebar,
193 int64_t pixel, double position)
194 : LabelGUI(mwindow, timebar, pixel, get_y(mwindow, timebar), position)
197 PresentationGUI::~PresentationGUI()
201 TimeBar::TimeBar(MWindow *mwindow, BC_WindowBase *gui,
202 int x, int y, int w, int h)
203 : BC_SubWindow(x, y, w, h)
205 //printf("TimeBar::TimeBar %d %d %d %d\n", x, y, w, h);
207 this->mwindow = mwindow;
208 this->drag_label = 0;
209 label_edit = new LabelEdit(mwindow, mwindow->awindow, 0);
219 labels.remove_all_objects();
220 presentations.remove_all_objects();
223 void TimeBar::create_objects()
227 //printf("TimeBar::create_objects %d\n", __LINE__);
228 current_operation = TIMEBAR_NONE;
229 set_cursor(UPRIGHT_ARROW_CURSOR, 0, 0);
234 int64_t TimeBar::position_to_pixel(double position)
237 return (int64_t)(position / time_per_pixel);
241 double TimeBar::pixel_to_position(int pixel)
244 pixel += get_edl()->local_session->view_start[pane->number];
247 return (double)pixel *
248 get_edl()->local_session->zoom_sample /
249 get_edl()->session->sample_rate;
252 void TimeBar::update_labels()
255 EDL *edl = get_edl();
258 for( Label *current=edl->labels->first; current; current=NEXT ) {
259 int64_t pixel = position_to_pixel(current->position);
260 if( pixel >= 0 && pixel < get_w() ) {
262 if( output >= labels.total ) {
264 add_subwindow(new_label =
265 new LabelGUI(mwindow,
268 LabelGUI::get_y(mwindow, this),
270 new_label->set_cursor(INHERIT_CURSOR, 0, 0);
271 new_label->set_tooltip(current->textstr);
272 new_label->label = current;
273 labels.append(new_label);
276 // Reposition old label
278 LabelGUI *gui = labels.values[output];
279 if( gui->pixel != pixel ) {
287 labels.values[output]->position = current->position;
288 labels.values[output]->set_tooltip(current->textstr);
289 labels.values[output]->label = current;
292 if( edl->local_session->get_selectionstart(1) <= current->position &&
293 edl->local_session->get_selectionend(1) >= current->position )
294 labels.values[output]->update(1);
296 if( labels.values[output]->get_value() )
297 labels.values[output]->update(0);
304 // Delete excess labels
305 while(labels.total > output)
307 labels.remove_object();
310 // Get the labels to show
314 void TimeBar::update_highlights()
316 EDL *edl = get_edl();
318 for( int i = 0; i < labels.total; i++ ) {
319 LabelGUI *label = labels.values[i];
320 if( edl->equivalent(label->position,
321 edl->local_session->get_selectionstart(1)) ||
322 edl->equivalent(label->position,
323 edl->local_session->get_selectionend(1)) ) {
324 if( !label->get_value() ) label->update(1);
327 if( label->get_value() ) label->update(0);
330 if( edl->equivalent(edl->local_session->get_inpoint(),
331 edl->local_session->get_selectionstart(1)) ||
332 edl->equivalent(edl->local_session->get_inpoint(),
333 edl->local_session->get_selectionend(1)) ) {
334 if( in_point ) in_point->update(1);
337 if( in_point ) in_point->update(0);
339 if( edl->equivalent(edl->local_session->get_outpoint(),
340 edl->local_session->get_selectionstart(1)) ||
341 edl->equivalent(edl->local_session->get_outpoint(),
342 edl->local_session->get_selectionend(1)) ) {
343 if( out_point ) out_point->update(1);
346 if( out_point ) out_point->update(0);
348 draw_inout_highlight();
351 void TimeBar::draw_inout_highlight()
353 EDL *edl = get_edl();
354 if( !edl->local_session->inpoint_valid() ) return;
355 if( !edl->local_session->outpoint_valid() ) return;
356 double in_position = edl->local_session->get_inpoint();
357 double out_position = edl->local_session->get_outpoint();
358 if( in_position >= out_position ) return;
359 int in_x = position_to_pixel(in_position);
360 int out_x = position_to_pixel(out_position);
361 CLAMP(in_x, 0, get_w());
362 CLAMP(out_x, 0, get_w());
363 set_color(mwindow->theme->inout_highlight_color);
367 draw_line(in_x, get_h()-2*lw, out_x, get_h()-2*lw);
372 void TimeBar::update_points()
374 EDL *edl = get_edl();
375 int64_t pixel = !edl ? 0 :
376 position_to_pixel(edl->local_session->get_inpoint());
379 if( edl && edl->local_session->inpoint_valid() &&
380 pixel >= 0 && pixel < get_w() ) {
381 if( !EQUIV(edl->local_session->get_inpoint(), in_point->position) ||
382 in_point->pixel != pixel ) {
383 in_point->pixel = pixel;
384 in_point->position = edl->local_session->get_inpoint();
385 in_point->reposition(0);
388 in_point->draw_face(1, 0);
397 if( edl && edl->local_session->inpoint_valid() &&
398 pixel >= 0 && pixel < get_w() ) {
399 add_subwindow(in_point = new InPointGUI(mwindow,
400 this, pixel, edl->local_session->get_inpoint()));
401 in_point->set_cursor(ARROW_CURSOR, 0, 0);
405 position_to_pixel(edl->local_session->get_outpoint());
408 if( edl && edl->local_session->outpoint_valid() &&
409 pixel >= 0 && pixel < get_w()) {
410 if( !EQUIV(edl->local_session->get_outpoint(), out_point->position) ||
411 out_point->pixel != pixel ) {
412 out_point->pixel = pixel;
413 out_point->position = edl->local_session->get_outpoint();
414 out_point->reposition(0);
417 out_point->draw_face(1, 0);
426 if( edl && edl->local_session->outpoint_valid() &&
427 pixel >= 0 && pixel < get_w() ) {
428 add_subwindow(out_point = new OutPointGUI(mwindow,
429 this, pixel, edl->local_session->get_outpoint()));
430 out_point->set_cursor(ARROW_CURSOR, 0, 0);
436 void TimeBar::update_clock(double position)
440 void TimeBar::update(int flush)
443 // Need to redo these when range is drawn to get the background updated.
448 EDL *edl = get_edl();
450 int x = get_relative_cursor_x();
451 // Draw highlight position
452 if( edl && (highlighted || current_operation == TIMEBAR_DRAG) &&
453 x >= 0 && x < get_w() ) {
454 //printf("TimeBar::update %d %d\n", __LINE__, x);
455 double position = pixel_to_position(x);
457 position = mwindow->edl->align_to_frame(position, 0);
458 pixel = position_to_pixel(position);
459 update_clock(position);
463 double position = test_highlight();
464 if( position >= 0 ) pixel = position_to_pixel(position);
468 if( pixel >= 0 && pixel < get_w() ) {
469 set_color(mwindow->theme->timebar_cursor_color);
471 //printf("TimeBar::update %d pane=%d pixel=%jd\n", __LINE__, pane->number, pixel);
472 draw_line(pixel, 0, pixel, get_h());
478 double playback_start = edl->local_session->playback_start;
479 if( playback_start >= 0 ) {
480 int64_t pixel = position_to_pixel(playback_start);
481 set_color(mwindow->theme->timebar_cursor_color ^ 0x0000ff);
482 draw_line(pixel, 0, pixel, get_h());
483 double playback_end = edl->local_session->playback_end;
484 if( playback_end > playback_start ) {
485 pixel = position_to_pixel(playback_end);
486 set_color(mwindow->theme->timebar_cursor_color ^ 0x00ff00);
487 draw_line(pixel, 0, pixel, get_h());
491 double position = edl->local_session->get_selectionstart(1);
492 int64_t pixel = position_to_pixel(position);
493 // Draw insertion point position.
494 int color = mwindow->theme->timebar_cursor_color;
495 if( mwindow->preferences->forward_render_displacement )
498 draw_line(pixel, 0, pixel, get_h());
503 // Get the labels to show
506 //printf("TimeBar::update %d this=%p %d\n", __LINE__, this, current_operation);
511 int TimeBar::delete_project()
513 // labels->delete_all();
517 int TimeBar::save(FileXML *xml)
519 // labels->save(xml);
526 void TimeBar::draw_time()
530 EDL* TimeBar::get_edl()
537 void TimeBar::draw_range()
541 //printf("TimeBar::draw_range %d %p\n", __LINE__, get_edl());
542 if( has_preview() && get_edl() ) {
544 get_preview_pixels(x1, x2);
546 //printf("TimeBar::draw_range %f %d %d\n", edl_length, x1, x2);
547 draw_3segmenth(0, 0, x1, mwindow->theme->timebar_view_data);
548 draw_top_background(get_parent(), x1, 0, x2 - x1, get_h());
549 draw_3segmenth(x2, 0, get_w() - x2, mwindow->theme->timebar_view_data);
552 draw_line(x1, 0, x1, get_h());
553 draw_line(x2, 0, x2, get_h());
556 EDL *edl = get_edl();
558 int64_t pixel = position_to_pixel(
559 edl->local_session->get_selectionstart(1));
560 // Draw insertion point position if this timebar belongs to a window which
561 // has something other than the master EDL.
562 set_color(mwindow->theme->timebar_cursor_color);
563 draw_line(pixel, 0, pixel, get_h());
567 draw_top_background(get_parent(), 0, 0, get_w(), get_h());
570 void TimeBar::select_label(double position)
581 double TimeBar::get_edl_length()
583 edl_length = get_edl() ? get_edl()->tracks->total_length() : 0;
585 time_per_pixel = !EQUIV(edl_length, 0) ? edl_length/w1 : w1;
589 int TimeBar::get_preview_pixels(int &x1, int &x2)
591 x1 = 0; x2 = get_w();
593 EDL *edl = get_edl();
594 if( edl && !EQUIV(edl_length, 0) ) {
595 double preview_start = edl->local_session->preview_start;
596 double preview_end = edl->local_session->preview_end;
597 if( preview_end < 0 || preview_end > edl_length )
598 preview_end = edl_length;
599 if( preview_end >= preview_start ) {
600 x1 = (int)(preview_start / time_per_pixel);
601 x2 = (int)(preview_end / time_per_pixel);
608 int TimeBar::test_preview(int buttonpress)
613 if( get_edl() && cursor_inside() && buttonpress >= 0 ) {
614 int x1, x2, x = get_relative_cursor_x();
615 get_preview_pixels(x1, x2);
616 //printf("TimeBar::test_preview %d %d %d\n", x1, x2, x);
617 // Inside left handle
618 if( x >= x1 - HANDLE_W && x < x1 + HANDLE_W &&
619 // Ignore left handle if both handles are up against the left side
622 current_operation = TIMEBAR_DRAG_LEFT;
623 start_position = get_edl()->local_session->preview_start;
626 else if( get_cursor() != LEFT_CURSOR )
627 set_cursor(LEFT_CURSOR, 0, 1);
630 // Inside right handle
631 else if( x >= x2 - HANDLE_W && x < x2 + HANDLE_W &&
632 // Ignore right handle if both handles are up against the right side
633 x1 < get_w() - HANDLE_W ) {
635 current_operation = TIMEBAR_DRAG_RIGHT;
636 start_position = get_edl()->local_session->preview_end;
637 if( start_position < 0 || start_position > edl_length )
638 start_position = edl_length;
641 else if( get_cursor() != RIGHT_CURSOR )
642 set_cursor(RIGHT_CURSOR, 0, 1);
646 else if( get_button_down() && get_buttonpress() == 3 &&
647 x >= x1 && x < x2 ) {
649 current_operation = TIMEBAR_DRAG_CENTER;
650 starting_start_position = get_edl()->local_session->preview_start;
651 starting_end_position = get_edl()->local_session->preview_end;
652 if( starting_end_position < 0 || starting_end_position > edl_length )
653 starting_end_position = edl_length;
656 if( get_cursor() != HSEPARATE_CURSOR )
657 set_cursor(HSEPARATE_CURSOR, 0, 1);
662 if( !result && get_cursor() != ARROW_CURSOR )
663 set_cursor(ARROW_CURSOR, 0, 1);
669 int TimeBar::move_preview(int &redraw)
671 int result = 0, x = get_relative_cursor_x();
672 switch( current_operation ) {
673 case TIMEBAR_DRAG_LEFT: {
674 get_edl()->local_session->preview_start =
675 start_position + time_per_pixel * (x - start_cursor_x);
676 double preview_end = get_edl()->local_session->preview_end;
677 if( preview_end < 0 || preview_end > edl_length )
678 preview_end = get_edl()->local_session->preview_end = edl_length;
679 CLAMP(get_edl()->local_session->preview_start, 0, preview_end);
682 case TIMEBAR_DRAG_RIGHT: {
683 double preview_end = get_edl()->local_session->preview_end =
684 start_position + time_per_pixel * (x - start_cursor_x);
685 double preview_start = get_edl()->local_session->preview_start;
686 if( preview_end >= edl_length && !preview_start ) {
687 get_edl()->local_session->preview_end = -1;
688 if( preview_start > preview_end )
689 preview_start = get_edl()->local_session->preview_start = preview_end;
692 CLAMP(get_edl()->local_session->preview_end, preview_start, edl_length);
695 case TIMEBAR_DRAG_CENTER: {
696 double dt = time_per_pixel * (x - start_cursor_x);
697 get_edl()->local_session->preview_start = starting_start_position + dt;
698 get_edl()->local_session->preview_end = starting_end_position + dt;
699 if( get_edl()->local_session->preview_start < 0 ) {
700 get_edl()->local_session->preview_end -= get_edl()->local_session->preview_start;
701 get_edl()->local_session->preview_start = 0;
704 if( get_edl()->local_session->preview_end > edl_length ) {
705 get_edl()->local_session->preview_start -= get_edl()->local_session->preview_end - edl_length;
706 get_edl()->local_session->preview_end = edl_length;
712 //printf("TimeBar::move_preview %d %d\n", __LINE__, current_operation);
718 //printf("TimeBar::move_preview %d %d\n", __LINE__, current_operation);
723 void TimeBar::update_preview()
727 int TimeBar::samplemovement()
732 void TimeBar::stop_playback()
736 int TimeBar::button_press_event()
739 if( is_event_win() && cursor_above() ) {
740 if( has_preview() && get_buttonpress() == 3 ) {
741 result = test_preview(1);
743 // Change time format
744 else if( ctrl_down() ) {
745 if( get_buttonpress() == 1 )
746 mwindow->next_time_format();
748 if( get_buttonpress() == 2 )
749 mwindow->prev_time_format();
752 else if( get_buttonpress() == 1 ) {
755 // Select region between two labels
756 if( !is_vwindow() && get_double_click() ) {
757 int x = get_relative_cursor_x();
758 double position = pixel_to_position(x);
760 select_region(position);
764 // Reposition highlight cursor
766 current_operation = TIMEBAR_DRAG;
775 void TimeBar::activate_timeline()
777 mwindow->gui->activate_timeline();
780 int TimeBar::cursor_motion_event()
785 //printf("TimeBar::cursor_motion_event %d %p %d\n", __LINE__, this, current_operation);
786 switch( current_operation )
791 handle_mwindow_drag();
793 //printf("TimeBar::cursor_motion_event %d %d\n", __LINE__, current_operation);
798 case TIMEBAR_DRAG_LEFT:
799 case TIMEBAR_DRAG_RIGHT:
800 case TIMEBAR_DRAG_CENTER:
802 result = move_preview(redraw);
805 case TIMEBAR_DRAG_LABEL:
807 int pixel = get_relative_cursor_x();
808 double position = pixel_to_position(pixel);
809 if( drag_label->label )
810 drag_label->label->position = position;
811 else if( drag_label == in_point ) {
812 EDL *edl = get_edl();
813 edl->local_session->set_inpoint(position);
815 else if( drag_label == out_point ) {
816 EDL *edl = get_edl();
817 edl->local_session->set_outpoint(position);
825 if( cursor_above() ) {
830 //printf("TimeBar::cursor_motion_event 20\n");
832 result = test_preview(0);
833 //printf("TimeBar::cursor_motion_event 30\n");
838 //printf("TimeBar::cursor_motion_event %d %d\n", __LINE__, current_operation);
842 //printf("TimeBar::cursor_motion_event %d %p %d\n", __LINE__, this, current_operation);
847 int TimeBar::cursor_leave_event()
856 int TimeBar::button_release_event()
858 //printf("TimeBar::button_release_event %d %d\n", __LINE__, current_operation);
861 switch( current_operation )
864 mwindow->gui->get_focused_pane()->canvas->stop_dragscroll();
865 current_operation = TIMEBAR_NONE;
871 if( current_operation != TIMEBAR_NONE ) {
872 current_operation = TIMEBAR_NONE;
878 if( (!cursor_above() && highlighted) || need_redraw ) {
886 // Update the selection cursor during a dragging operation
887 void TimeBar::update_cursor()
891 void TimeBar::handle_mwindow_drag()
895 int TimeBar::select_region(double position)
897 Label *start = 0, *end = 0, *current;
898 for( current = get_edl()->labels->first; current; current = NEXT ) {
899 if( current->position > position ) {
905 for( current = get_edl()->labels->last ; current; current = PREVIOUS ) {
906 if( current->position <= position ) {
915 get_edl()->local_session->set_selectionstart(0);
917 get_edl()->local_session->set_selectionstart(start->position);
920 get_edl()->local_session->set_selectionend(get_edl()->tracks->total_length());
922 get_edl()->local_session->set_selectionend(end->position);
926 get_edl()->local_session->set_selectionstart(start->position);
927 get_edl()->local_session->set_selectionend(start->position);
931 mwindow->cwindow->gui->lock_window("TimeBar::select_region");
932 mwindow->cwindow->update(1, 0, 0);
933 mwindow->cwindow->gui->unlock_window();
934 mwindow->gui->lock_window("TimeBar::select_region");
935 mwindow->gui->hide_cursor(0);
936 mwindow->gui->draw_cursor(1);
937 mwindow->gui->flash_canvas(0);
938 mwindow->gui->activate_timeline();
939 mwindow->gui->zoombar->update();
940 mwindow->gui->unlock_window();
948 int TimeBar::delete_arrows()
953 double TimeBar::test_highlight()