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;
76 int LabelGUI::get_y(MWindow *mwindow, TimeBar *timebar)
78 return timebar->get_h() -
79 mwindow->theme->label_toggle[0]->get_h();
82 int LabelGUI::translate_pixel(MWindow *mwindow, int pixel)
84 int result = pixel - mwindow->theme->label_toggle[0]->get_w() / 2;
88 void LabelGUI::reposition(int flush)
90 reposition_window(translate_pixel(mwindow, pixel),
94 int LabelGUI::button_press_event()
98 if( this->is_event_win() && get_buttonpress() == 3 ) {
101 get_abs_cursor(cur_x, cur_y, 0);
102 timebar->label_edit->start(label, cur_x, cur_y);
106 result = BC_Toggle::button_press_event();
109 set_tooltip(this->label->textstr);
113 int LabelGUI::handle_event()
115 timebar->select_label(position);
120 InPointGUI::InPointGUI(MWindow *mwindow, TimeBar *timebar,
121 int64_t pixel, double position)
122 : LabelGUI(mwindow, timebar,
123 pixel, get_y(mwindow, timebar),
124 position, mwindow->theme->in_point)
126 //printf("InPointGUI::InPointGUI %d %d\n", pixel, get_y(mwindow, timebar));
128 InPointGUI::~InPointGUI()
131 int InPointGUI::get_y(MWindow *mwindow, TimeBar *timebar)
134 result = timebar->get_h() -
135 mwindow->theme->in_point[0]->get_h();
140 OutPointGUI::OutPointGUI(MWindow *mwindow, TimeBar *timebar,
141 int64_t pixel, double position)
142 : LabelGUI(mwindow, timebar,
143 pixel, get_y(mwindow, timebar),
144 position, mwindow->theme->out_point)
146 //printf("OutPointGUI::OutPointGUI %d %d\n", pixel, get_y(mwindow, timebar));
148 OutPointGUI::~OutPointGUI()
151 int OutPointGUI::get_y(MWindow *mwindow, TimeBar *timebar)
153 return timebar->get_h() -
154 mwindow->theme->out_point[0]->get_h();
158 PresentationGUI::PresentationGUI(MWindow *mwindow, TimeBar *timebar,
159 int64_t pixel, double position)
160 : LabelGUI(mwindow, timebar, pixel, get_y(mwindow, timebar), position)
163 PresentationGUI::~PresentationGUI()
167 TimeBar::TimeBar(MWindow *mwindow, BC_WindowBase *gui,
168 int x, int y, int w, int h)
169 : BC_SubWindow(x, y, w, h)
171 //printf("TimeBar::TimeBar %d %d %d %d\n", x, y, w, h);
173 this->mwindow = mwindow;
174 label_edit = new LabelEdit(mwindow, mwindow->awindow, 0);
184 labels.remove_all_objects();
185 presentations.remove_all_objects();
188 void TimeBar::create_objects()
192 //printf("TimeBar::create_objects %d\n", __LINE__);
193 current_operation = TIMEBAR_NONE;
194 set_cursor(UPRIGHT_ARROW_CURSOR, 0, 0);
199 int64_t TimeBar::position_to_pixel(double position)
202 return (int64_t)(position / time_per_pixel);
206 double TimeBar::pixel_to_position(int pixel)
209 pixel += get_edl()->local_session->view_start[pane->number];
212 return (double)pixel *
213 get_edl()->local_session->zoom_sample /
214 get_edl()->session->sample_rate;
217 void TimeBar::update_labels()
220 EDL *edl = get_edl();
223 for( Label *current=edl->labels->first; current; current=NEXT ) {
224 int64_t pixel = position_to_pixel(current->position);
225 if( pixel >= 0 && pixel < get_w() ) {
227 if( output >= labels.total ) {
229 add_subwindow(new_label =
230 new LabelGUI(mwindow,
233 LabelGUI::get_y(mwindow, this),
235 new_label->set_cursor(INHERIT_CURSOR, 0, 0);
236 new_label->set_tooltip(current->textstr);
237 new_label->label = current;
238 labels.append(new_label);
241 // Reposition old label
243 LabelGUI *gui = labels.values[output];
244 if( gui->pixel != pixel ) {
252 labels.values[output]->position = current->position;
253 labels.values[output]->set_tooltip(current->textstr);
254 labels.values[output]->label = current;
257 if( edl->local_session->get_selectionstart(1) <= current->position &&
258 edl->local_session->get_selectionend(1) >= current->position )
259 labels.values[output]->update(1);
261 if( labels.values[output]->get_value() )
262 labels.values[output]->update(0);
269 // Delete excess labels
270 while(labels.total > output)
272 labels.remove_object();
275 // Get the labels to show
279 void TimeBar::update_highlights()
281 EDL *edl = get_edl();
283 for( int i = 0; i < labels.total; i++ ) {
284 LabelGUI *label = labels.values[i];
285 if( edl->equivalent(label->position,
286 edl->local_session->get_selectionstart(1)) ||
287 edl->equivalent(label->position,
288 edl->local_session->get_selectionend(1)) ) {
289 if( !label->get_value() ) label->update(1);
292 if( label->get_value() ) label->update(0);
295 if( edl->equivalent(edl->local_session->get_inpoint(),
296 edl->local_session->get_selectionstart(1)) ||
297 edl->equivalent(edl->local_session->get_inpoint(),
298 edl->local_session->get_selectionend(1)) ) {
299 if( in_point ) in_point->update(1);
302 if( in_point ) in_point->update(0);
304 if( edl->equivalent(edl->local_session->get_outpoint(),
305 edl->local_session->get_selectionstart(1)) ||
306 edl->equivalent(edl->local_session->get_outpoint(),
307 edl->local_session->get_selectionend(1)) ) {
308 if( out_point ) out_point->update(1);
311 if( out_point ) out_point->update(0);
314 void TimeBar::update_points()
316 EDL *edl = get_edl();
317 int64_t pixel = !edl ? 0 :
318 position_to_pixel(edl->local_session->get_inpoint());
321 if( edl && edl->local_session->inpoint_valid() &&
322 pixel >= 0 && pixel < get_w() ) {
323 if( !EQUIV(edl->local_session->get_inpoint(), in_point->position) ||
324 in_point->pixel != pixel ) {
325 in_point->pixel = pixel;
326 in_point->position = edl->local_session->get_inpoint();
327 in_point->reposition(0);
330 in_point->draw_face(1, 0);
339 if( edl && edl->local_session->inpoint_valid() &&
340 pixel >= 0 && pixel < get_w() ) {
341 add_subwindow(in_point = new InPointGUI(mwindow,
342 this, pixel, edl->local_session->get_inpoint()));
343 in_point->set_cursor(ARROW_CURSOR, 0, 0);
347 position_to_pixel(edl->local_session->get_outpoint());
350 if( edl && edl->local_session->outpoint_valid() &&
351 pixel >= 0 && pixel < get_w()) {
352 if( !EQUIV(edl->local_session->get_outpoint(), out_point->position) ||
353 out_point->pixel != pixel ) {
354 out_point->pixel = pixel;
355 out_point->position = edl->local_session->get_outpoint();
356 out_point->reposition(0);
359 out_point->draw_face(1, 0);
368 if( edl && edl->local_session->outpoint_valid() &&
369 pixel >= 0 && pixel < get_w() ) {
370 add_subwindow(out_point = new OutPointGUI(mwindow,
371 this, pixel, edl->local_session->get_outpoint()));
372 out_point->set_cursor(ARROW_CURSOR, 0, 0);
378 void TimeBar::update_clock(double position)
382 void TimeBar::update(int flush)
385 // Need to redo these when range is drawn to get the background updated.
390 EDL *edl = get_edl();
392 int x = get_relative_cursor_x();
393 // Draw highlight position
394 if( edl && (highlighted || current_operation == TIMEBAR_DRAG) &&
395 x >= 0 && x < get_w() ) {
396 //printf("TimeBar::update %d %d\n", __LINE__, x);
397 double position = pixel_to_position(x);
399 position = mwindow->edl->align_to_frame(position, 0);
400 pixel = position_to_pixel(position);
401 update_clock(position);
405 double position = test_highlight();
406 if( position >= 0 ) pixel = position_to_pixel(position);
410 if( pixel >= 0 && pixel < get_w() ) {
411 set_color(mwindow->theme->timebar_cursor_color);
413 //printf("TimeBar::update %d pane=%d pixel=%jd\n", __LINE__, pane->number, pixel);
414 draw_line(pixel, 0, pixel, get_h());
420 double playback_start = edl->local_session->playback_start;
421 if( playback_start >= 0 ) {
422 int64_t pixel = position_to_pixel(playback_start);
423 set_color(mwindow->theme->timebar_cursor_color ^ 0x0000ff);
424 draw_line(pixel, 0, pixel, get_h());
425 double playback_end = edl->local_session->playback_end;
426 if( playback_end > playback_start ) {
427 pixel = position_to_pixel(playback_end);
428 set_color(mwindow->theme->timebar_cursor_color ^ 0x00ff00);
429 draw_line(pixel, 0, pixel, get_h());
433 double position = edl->local_session->get_selectionstart(1);
434 int64_t pixel = position_to_pixel(position);
435 // Draw insertion point position.
436 int color = mwindow->theme->timebar_cursor_color;
437 if( mwindow->preferences->forward_render_displacement )
440 draw_line(pixel, 0, pixel, get_h());
445 // Get the labels to show
448 //printf("TimeBar::update %d this=%p %d\n", __LINE__, this, current_operation);
453 int TimeBar::delete_project()
455 // labels->delete_all();
459 int TimeBar::save(FileXML *xml)
461 // labels->save(xml);
468 void TimeBar::draw_time()
472 EDL* TimeBar::get_edl()
479 void TimeBar::draw_range()
483 //printf("TimeBar::draw_range %d %p\n", __LINE__, get_edl());
484 if( has_preview() && get_edl() ) {
486 get_preview_pixels(x1, x2);
488 //printf("TimeBar::draw_range %f %d %d\n", edl_length, x1, x2);
489 draw_3segmenth(0, 0, x1, mwindow->theme->timebar_view_data);
490 draw_top_background(get_parent(), x1, 0, x2 - x1, get_h());
491 draw_3segmenth(x2, 0, get_w() - x2, mwindow->theme->timebar_view_data);
494 draw_line(x1, 0, x1, get_h());
495 draw_line(x2, 0, x2, get_h());
498 EDL *edl = get_edl();
500 int64_t pixel = position_to_pixel(
501 edl->local_session->get_selectionstart(1));
502 // Draw insertion point position if this timebar belongs to a window which
503 // has something other than the master EDL.
504 set_color(mwindow->theme->timebar_cursor_color);
505 draw_line(pixel, 0, pixel, get_h());
509 draw_top_background(get_parent(), 0, 0, get_w(), get_h());
512 void TimeBar::select_label(double position)
523 double TimeBar::get_edl_length()
525 edl_length = get_edl() ? get_edl()->tracks->total_length() : 0;
527 time_per_pixel = !EQUIV(edl_length, 0) ? edl_length/w1 : w1;
531 int TimeBar::get_preview_pixels(int &x1, int &x2)
533 x1 = 0; x2 = get_w();
535 EDL *edl = get_edl();
536 if( edl && !EQUIV(edl_length, 0) ) {
537 double preview_start = edl->local_session->preview_start;
538 double preview_end = edl->local_session->preview_end;
539 if( preview_end < 0 || preview_end > edl_length )
540 preview_end = edl_length;
541 if( preview_end >= preview_start ) {
542 x1 = (int)(preview_start / time_per_pixel);
543 x2 = (int)(preview_end / time_per_pixel);
550 int TimeBar::test_preview(int buttonpress)
555 if( get_edl() && cursor_inside() && buttonpress >= 0 ) {
556 int x1, x2, x = get_relative_cursor_x();
557 get_preview_pixels(x1, x2);
558 //printf("TimeBar::test_preview %d %d %d\n", x1, x2, x);
559 // Inside left handle
560 if( x >= x1 - HANDLE_W && x < x1 + HANDLE_W &&
561 // Ignore left handle if both handles are up against the left side
564 current_operation = TIMEBAR_DRAG_LEFT;
565 start_position = get_edl()->local_session->preview_start;
568 else if( get_cursor() != LEFT_CURSOR )
569 set_cursor(LEFT_CURSOR, 0, 1);
572 // Inside right handle
573 else if( x >= x2 - HANDLE_W && x < x2 + HANDLE_W &&
574 // Ignore right handle if both handles are up against the right side
575 x1 < get_w() - HANDLE_W ) {
577 current_operation = TIMEBAR_DRAG_RIGHT;
578 start_position = get_edl()->local_session->preview_end;
579 if( start_position < 0 || start_position > edl_length )
580 start_position = edl_length;
583 else if( get_cursor() != RIGHT_CURSOR )
584 set_cursor(RIGHT_CURSOR, 0, 1);
588 else if( get_button_down() && get_buttonpress() == 3 &&
589 x >= x1 && x < x2 ) {
591 current_operation = TIMEBAR_DRAG_CENTER;
592 starting_start_position = get_edl()->local_session->preview_start;
593 starting_end_position = get_edl()->local_session->preview_end;
594 if( starting_end_position < 0 || starting_end_position > edl_length )
595 starting_end_position = edl_length;
598 if( get_cursor() != HSEPARATE_CURSOR )
599 set_cursor(HSEPARATE_CURSOR, 0, 1);
604 if( !result && get_cursor() != ARROW_CURSOR )
605 set_cursor(ARROW_CURSOR, 0, 1);
611 int TimeBar::move_preview(int &redraw)
613 int result = 0, x = get_relative_cursor_x();
614 switch( current_operation ) {
615 case TIMEBAR_DRAG_LEFT: {
616 get_edl()->local_session->preview_start =
617 start_position + time_per_pixel * (x - start_cursor_x);
618 double preview_end = get_edl()->local_session->preview_end;
619 if( preview_end < 0 || preview_end > edl_length )
620 preview_end = get_edl()->local_session->preview_end = edl_length;
621 CLAMP(get_edl()->local_session->preview_start, 0, preview_end);
624 case TIMEBAR_DRAG_RIGHT: {
625 double preview_end = get_edl()->local_session->preview_end =
626 start_position + time_per_pixel * (x - start_cursor_x);
627 double preview_start = get_edl()->local_session->preview_start;
628 if( preview_end >= edl_length && !preview_start ) {
629 get_edl()->local_session->preview_end = -1;
630 if( preview_start > preview_end )
631 preview_start = get_edl()->local_session->preview_start = preview_end;
634 CLAMP(get_edl()->local_session->preview_end, preview_start, edl_length);
637 case TIMEBAR_DRAG_CENTER: {
638 double dt = time_per_pixel * (x - start_cursor_x);
639 get_edl()->local_session->preview_start = starting_start_position + dt;
640 get_edl()->local_session->preview_end = starting_end_position + dt;
641 if( get_edl()->local_session->preview_start < 0 ) {
642 get_edl()->local_session->preview_end -= get_edl()->local_session->preview_start;
643 get_edl()->local_session->preview_start = 0;
646 if( get_edl()->local_session->preview_end > edl_length ) {
647 get_edl()->local_session->preview_start -= get_edl()->local_session->preview_end - edl_length;
648 get_edl()->local_session->preview_end = edl_length;
654 //printf("TimeBar::move_preview %d %d\n", __LINE__, current_operation);
660 //printf("TimeBar::move_preview %d %d\n", __LINE__, current_operation);
665 void TimeBar::update_preview()
669 int TimeBar::samplemovement()
674 void TimeBar::stop_playback()
678 int TimeBar::button_press_event()
681 if( is_event_win() && cursor_above() ) {
682 if( has_preview() && get_buttonpress() == 3 ) {
683 result = test_preview(1);
685 // Change time format
686 else if( ctrl_down() ) {
687 if( get_buttonpress() == 1 )
688 mwindow->next_time_format();
690 if( get_buttonpress() == 2 )
691 mwindow->prev_time_format();
694 else if( get_buttonpress() == 1 ) {
697 // Select region between two labels
698 if( !is_vwindow() && get_double_click() ) {
699 int x = get_relative_cursor_x();
700 double position = pixel_to_position(x);
702 select_region(position);
706 // Reposition highlight cursor
708 current_operation = TIMEBAR_DRAG;
717 void TimeBar::activate_timeline()
719 mwindow->gui->activate_timeline();
722 int TimeBar::cursor_motion_event()
727 //printf("TimeBar::cursor_motion_event %d %p %d\n", __LINE__, this, current_operation);
728 switch( current_operation )
733 handle_mwindow_drag();
735 //printf("TimeBar::cursor_motion_event %d %d\n", __LINE__, current_operation);
740 case TIMEBAR_DRAG_LEFT:
741 case TIMEBAR_DRAG_RIGHT:
742 case TIMEBAR_DRAG_CENTER:
744 result = move_preview(redraw);
748 if( cursor_above() ) {
753 //printf("TimeBar::cursor_motion_event 20\n");
755 result = test_preview(0);
756 //printf("TimeBar::cursor_motion_event 30\n");
761 //printf("TimeBar::cursor_motion_event %d %d\n", __LINE__, current_operation);
765 //printf("TimeBar::cursor_motion_event %d %p %d\n", __LINE__, this, current_operation);
770 int TimeBar::cursor_leave_event()
779 int TimeBar::button_release_event()
781 //printf("TimeBar::button_release_event %d %d\n", __LINE__, current_operation);
784 switch( current_operation )
787 mwindow->gui->get_focused_pane()->canvas->stop_dragscroll();
788 current_operation = TIMEBAR_NONE;
794 if( current_operation != TIMEBAR_NONE ) {
795 current_operation = TIMEBAR_NONE;
801 if( (!cursor_above() && highlighted) || need_redraw ) {
809 // Update the selection cursor during a dragging operation
810 void TimeBar::update_cursor()
814 void TimeBar::handle_mwindow_drag()
818 int TimeBar::select_region(double position)
820 Label *start = 0, *end = 0, *current;
821 for( current = get_edl()->labels->first; current; current = NEXT ) {
822 if( current->position > position ) {
828 for( current = get_edl()->labels->last ; current; current = PREVIOUS ) {
829 if( current->position <= position ) {
838 get_edl()->local_session->set_selectionstart(0);
840 get_edl()->local_session->set_selectionstart(start->position);
843 get_edl()->local_session->set_selectionend(get_edl()->tracks->total_length());
845 get_edl()->local_session->set_selectionend(end->position);
849 get_edl()->local_session->set_selectionstart(start->position);
850 get_edl()->local_session->set_selectionend(start->position);
854 mwindow->cwindow->gui->lock_window("TimeBar::select_region");
855 mwindow->cwindow->update(1, 0, 0);
856 mwindow->cwindow->gui->unlock_window();
857 mwindow->gui->lock_window("TimeBar::select_region");
858 mwindow->gui->hide_cursor(0);
859 mwindow->gui->draw_cursor(1);
860 mwindow->gui->flash_canvas(0);
861 mwindow->gui->activate_timeline();
862 mwindow->gui->zoombar->update();
863 mwindow->gui->unlock_window();
871 int TimeBar::delete_arrows()
876 double TimeBar::test_highlight()