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
23 #include "awindowgui.h"
24 #include "bcsignals.h"
26 #include "cplayback.h"
29 #include "cwindowgui.h"
31 #include "edlsession.h"
35 #include "labeledit.h"
36 #include "localsession.h"
37 #include "maincursor.h"
41 #include "mwindowgui.h"
43 #include "preferences.h"
44 #include "recordlabel.h"
45 #include "localsession.h"
46 #include "mainsession.h"
49 #include "timelinepane.h"
50 #include "trackcanvas.h"
52 #include "transportque.h"
56 #include "vwindowgui.h"
60 LabelGUI::LabelGUI(MWindow *mwindow, TimeBar *timebar,
62 double position, VFrame **data)
63 : BC_Toggle(translate_pixel(mwindow, pixel), y,
64 data ? data : mwindow->theme->label_toggle, 0)
66 this->mwindow = mwindow;
67 this->timebar = timebar;
70 this->position = position;
76 if( timebar->drag_label == this )
77 timebar->drag_label = 0;
80 int LabelGUI::get_y(MWindow *mwindow, TimeBar *timebar)
82 return timebar->get_h() -
83 mwindow->theme->label_toggle[0]->get_h();
86 int LabelGUI::translate_pixel(MWindow *mwindow, int pixel)
88 int result = pixel - mwindow->theme->label_toggle[0]->get_w() / 2;
92 void LabelGUI::reposition(int flush)
94 reposition_window(translate_pixel(mwindow, pixel),
98 int LabelGUI::button_press_event()
100 int result = test_drag_label(1);
102 if( this->is_event_win() && get_buttonpress() == 3 ) {
105 get_abs_cursor(cur_x, cur_y, 0);
106 timebar->label_edit->start(label, cur_x, cur_y);
110 result = BC_Toggle::button_press_event();
113 set_tooltip(this->label->textstr);
117 int LabelGUI::button_release_event()
119 int ret = BC_Toggle::button_release_event();
124 int LabelGUI::test_drag_label(int press)
126 if( is_event_win() && get_buttonpress() == 1 ) {
127 switch( timebar->current_operation ) {
129 if( press && get_value() ) {
130 timebar->current_operation = TIMEBAR_DRAG_LABEL;
131 timebar->drag_label = this;
132 set_cursor(HSEPARATE_CURSOR, 0, 0);
133 mwindow->undo->update_undo_before(_("drag label"), this);
137 case TIMEBAR_DRAG_LABEL:
139 timebar->current_operation = TIMEBAR_NONE;
140 timebar->drag_label = 0;
141 set_cursor(ARROW_CURSOR, 0, 0);
142 mwindow->undo->update_undo_after(_("drag label"), LOAD_TIMEBAR);
143 mwindow->awindow->gui->async_update_assets(); // labels folder
151 int LabelGUI::handle_event()
153 timebar->select_label(position);
157 void LabelGUI::update_value()
159 EDL *edl = timebar->get_edl();
160 double start = edl->local_session->get_selectionstart(1);
161 double end = edl->local_session->get_selectionend(1);
162 int v = ( label->position >= start && end >= label->position ) ||
163 edl->equivalent(label->position, start) ||
164 edl->equivalent(label->position, end) ||
165 timebar->drag_label == this ? 1 : 0;
170 InPointGUI::InPointGUI(MWindow *mwindow, TimeBar *timebar,
171 int64_t pixel, double position)
172 : LabelGUI(mwindow, timebar,
173 pixel, get_y(mwindow, timebar),
174 position, mwindow->theme->in_point)
176 //printf("InPointGUI::InPointGUI %d %d\n", pixel, get_y(mwindow, timebar));
178 InPointGUI::~InPointGUI()
181 int InPointGUI::get_y(MWindow *mwindow, TimeBar *timebar)
184 result = timebar->get_h() -
185 mwindow->theme->in_point[0]->get_h();
190 OutPointGUI::OutPointGUI(MWindow *mwindow, TimeBar *timebar,
191 int64_t pixel, double position)
192 : LabelGUI(mwindow, timebar,
193 pixel, get_y(mwindow, timebar),
194 position, mwindow->theme->out_point)
196 //printf("OutPointGUI::OutPointGUI %d %d\n", pixel, get_y(mwindow, timebar));
198 OutPointGUI::~OutPointGUI()
201 int OutPointGUI::get_y(MWindow *mwindow, TimeBar *timebar)
203 return timebar->get_h() -
204 mwindow->theme->out_point[0]->get_h();
208 PresentationGUI::PresentationGUI(MWindow *mwindow, TimeBar *timebar,
209 int64_t pixel, double position)
210 : LabelGUI(mwindow, timebar, pixel, get_y(mwindow, timebar), position)
213 PresentationGUI::~PresentationGUI()
217 TimeBar::TimeBar(MWindow *mwindow, BC_WindowBase *gui,
218 int x, int y, int w, int h)
219 : BC_SubWindow(x, y, w, h)
221 //printf("TimeBar::TimeBar %d %d %d %d\n", x, y, w, h);
223 this->mwindow = mwindow;
224 this->drag_label = 0;
225 label_edit = new LabelEdit(mwindow, mwindow->awindow, 0);
235 labels.remove_all_objects();
236 presentations.remove_all_objects();
239 void TimeBar::create_objects()
243 //printf("TimeBar::create_objects %d\n", __LINE__);
244 current_operation = TIMEBAR_NONE;
245 set_cursor(UPRIGHT_ARROW_CURSOR, 0, 0);
250 int64_t TimeBar::position_to_pixel(double position)
253 return (int64_t)(position / time_per_pixel);
257 double TimeBar::pixel_to_position(int pixel)
260 pixel += get_edl()->local_session->view_start[pane->number];
263 return (double)pixel *
264 get_edl()->local_session->zoom_sample /
265 get_edl()->session->sample_rate;
268 void TimeBar::update_labels()
271 EDL *edl = get_edl();
274 for( Label *current=edl->labels->first; current; current=NEXT ) {
275 int64_t pixel = position_to_pixel(current->position);
276 if( pixel >= 0 && pixel < get_w() ) {
278 if( output >= labels.total ) {
280 add_subwindow(new_label =
281 new LabelGUI(mwindow,
284 LabelGUI::get_y(mwindow, this),
286 new_label->set_cursor(INHERIT_CURSOR, 0, 0);
287 new_label->set_tooltip(current->textstr);
288 new_label->label = current;
289 labels.append(new_label);
292 // Reposition old label
294 LabelGUI *gui = labels.values[output];
295 if( gui->pixel != pixel ) {
300 // gui->draw_face(1,0);
303 labels.values[output]->position = current->position;
304 labels.values[output]->set_tooltip(current->textstr);
305 labels.values[output]->label = current;
308 labels.values[output++]->update_value();
313 // Delete excess labels
314 while(labels.total > output)
316 labels.remove_object();
319 // Get the labels to show
323 void TimeBar::update_highlights()
325 EDL *edl = get_edl();
327 for( int i = 0; i < labels.total; i++ ) {
328 labels.values[i]->update_value();
331 if( edl->equivalent(edl->local_session->get_inpoint(),
332 edl->local_session->get_selectionstart(1)) ||
333 edl->equivalent(edl->local_session->get_inpoint(),
334 edl->local_session->get_selectionend(1)) ) {
335 if( in_point ) in_point->update(1);
338 if( in_point ) in_point->update(0);
340 if( edl->equivalent(edl->local_session->get_outpoint(),
341 edl->local_session->get_selectionstart(1)) ||
342 edl->equivalent(edl->local_session->get_outpoint(),
343 edl->local_session->get_selectionend(1)) ) {
344 if( out_point ) out_point->update(1);
347 if( out_point ) out_point->update(0);
349 draw_inout_highlight();
352 void TimeBar::draw_inout_highlight()
354 EDL *edl = get_edl();
355 if( !edl->local_session->inpoint_valid() ) return;
356 if( !edl->local_session->outpoint_valid() ) return;
357 double in_position = edl->local_session->get_inpoint();
358 double out_position = edl->local_session->get_outpoint();
359 if( in_position >= out_position ) return;
360 int in_x = position_to_pixel(in_position);
361 int out_x = position_to_pixel(out_position);
362 CLAMP(in_x, 0, get_w());
363 CLAMP(out_x, 0, get_w());
364 set_color(mwindow->theme->inout_highlight_color);
368 draw_line(in_x, get_h()-2*lw, out_x, get_h()-2*lw);
373 void TimeBar::update_points()
375 EDL *edl = get_edl();
376 int64_t pixel = !edl ? 0 :
377 position_to_pixel(edl->local_session->get_inpoint());
380 if( edl && edl->local_session->inpoint_valid() &&
381 pixel >= 0 && pixel < get_w() ) {
382 if( !EQUIV(edl->local_session->get_inpoint(), in_point->position) ||
383 in_point->pixel != pixel ) {
384 in_point->pixel = pixel;
385 in_point->position = edl->local_session->get_inpoint();
386 in_point->reposition(0);
389 in_point->draw_face(1, 0);
398 if( edl && edl->local_session->inpoint_valid() &&
399 pixel >= 0 && pixel < get_w() ) {
400 add_subwindow(in_point = new InPointGUI(mwindow,
401 this, pixel, edl->local_session->get_inpoint()));
402 in_point->set_cursor(ARROW_CURSOR, 0, 0);
406 position_to_pixel(edl->local_session->get_outpoint());
409 if( edl && edl->local_session->outpoint_valid() &&
410 pixel >= 0 && pixel < get_w()) {
411 if( !EQUIV(edl->local_session->get_outpoint(), out_point->position) ||
412 out_point->pixel != pixel ) {
413 out_point->pixel = pixel;
414 out_point->position = edl->local_session->get_outpoint();
415 out_point->reposition(0);
418 out_point->draw_face(1, 0);
427 if( edl && edl->local_session->outpoint_valid() &&
428 pixel >= 0 && pixel < get_w() ) {
429 add_subwindow(out_point = new OutPointGUI(mwindow,
430 this, pixel, edl->local_session->get_outpoint()));
431 out_point->set_cursor(ARROW_CURSOR, 0, 0);
437 void TimeBar::update_clock(double position)
441 void TimeBar::update(int flush)
444 // Need to redo these when range is drawn to get the background updated.
449 EDL *edl = get_edl();
451 int x = get_relative_cursor_x();
452 // Draw highlight position
453 if( edl && (highlighted || current_operation == TIMEBAR_DRAG) &&
454 x >= 0 && x < get_w() ) {
455 //printf("TimeBar::update %d %d\n", __LINE__, x);
456 double position = pixel_to_position(x);
458 position = mwindow->edl->align_to_frame(position, 0);
459 pixel = position_to_pixel(position);
460 update_clock(position);
464 double position = test_highlight();
465 if( position >= 0 ) pixel = position_to_pixel(position);
469 if( pixel >= 0 && pixel < get_w() ) {
470 set_color(mwindow->theme->timebar_cursor_color);
472 //printf("TimeBar::update %d pane=%d pixel=%jd\n", __LINE__, pane->number, pixel);
473 draw_line(pixel, 0, pixel, get_h());
479 double playback_start = edl->local_session->playback_start;
480 if( playback_start >= 0 ) {
481 int64_t pixel = position_to_pixel(playback_start);
482 set_color(mwindow->theme->timebar_cursor_color ^ 0x0000ff);
483 draw_line(pixel, 0, pixel, get_h());
484 double playback_end = edl->local_session->playback_end;
485 if( playback_end > playback_start ) {
486 pixel = position_to_pixel(playback_end);
487 set_color(mwindow->theme->timebar_cursor_color ^ 0x00ff00);
488 draw_line(pixel, 0, pixel, get_h());
492 double position = edl->local_session->get_selectionstart(1);
493 int64_t pixel = position_to_pixel(position);
494 // Draw insertion point position.
495 int color = mwindow->theme->timebar_cursor_color;
496 if( mwindow->preferences->forward_render_displacement )
499 draw_line(pixel, 0, pixel, get_h());
504 // Get the labels to show
507 //printf("TimeBar::update %d this=%p %d\n", __LINE__, this, current_operation);
512 int TimeBar::delete_project()
514 // labels->delete_all();
518 int TimeBar::save(FileXML *xml)
520 // labels->save(xml);
527 void TimeBar::draw_time()
531 EDL* TimeBar::get_edl()
538 void TimeBar::draw_range()
542 //printf("TimeBar::draw_range %d %p\n", __LINE__, get_edl());
543 if( has_preview() && get_edl() ) {
545 get_preview_pixels(x1, x2);
547 //printf("TimeBar::draw_range %f %d %d\n", edl_length, x1, x2);
548 draw_3segmenth(0, 0, x1, mwindow->theme->timebar_view_data);
549 draw_top_background(get_parent(), x1, 0, x2 - x1, get_h());
550 draw_3segmenth(x2, 0, get_w() - x2, mwindow->theme->timebar_view_data);
553 draw_line(x1, 0, x1, get_h());
554 draw_line(x2, 0, x2, get_h());
557 EDL *edl = get_edl();
559 int64_t pixel = position_to_pixel(
560 edl->local_session->get_selectionstart(1));
561 // Draw insertion point position if this timebar belongs to a window which
562 // has something other than the master EDL.
563 set_color(mwindow->theme->timebar_cursor_color);
564 draw_line(pixel, 0, pixel, get_h());
568 draw_top_background(get_parent(), 0, 0, get_w(), get_h());
571 void TimeBar::select_label(double position)
582 double TimeBar::get_edl_length()
584 edl_length = get_edl() ? get_edl()->tracks->total_length() : 0;
586 time_per_pixel = !EQUIV(edl_length, 0) ? edl_length/w1 : w1;
590 int TimeBar::get_preview_pixels(int &x1, int &x2)
592 x1 = 0; x2 = get_w();
594 EDL *edl = get_edl();
595 if( edl && !EQUIV(edl_length, 0) ) {
596 double preview_start = edl->local_session->preview_start;
597 double preview_end = edl->local_session->preview_end;
598 if( preview_end < 0 || preview_end > edl_length )
599 preview_end = edl_length;
600 if( preview_end >= preview_start ) {
601 x1 = (int)(preview_start / time_per_pixel);
602 x2 = (int)(preview_end / time_per_pixel);
609 int TimeBar::test_preview(int buttonpress)
614 if( get_edl() && cursor_inside() && buttonpress >= 0 ) {
615 int x1, x2, x = get_relative_cursor_x();
616 get_preview_pixels(x1, x2);
617 //printf("TimeBar::test_preview %d %d %d\n", x1, x2, x);
618 // Inside left handle
619 if( x >= x1 - HANDLE_W && x < x1 + HANDLE_W &&
620 // Ignore left handle if both handles are up against the left side
623 current_operation = TIMEBAR_DRAG_LEFT;
624 start_position = get_edl()->local_session->preview_start;
627 else if( get_cursor() != LEFT_CURSOR )
628 set_cursor(LEFT_CURSOR, 0, 1);
631 // Inside right handle
632 else if( x >= x2 - HANDLE_W && x < x2 + HANDLE_W &&
633 // Ignore right handle if both handles are up against the right side
634 x1 < get_w() - HANDLE_W ) {
636 current_operation = TIMEBAR_DRAG_RIGHT;
637 start_position = get_edl()->local_session->preview_end;
638 if( start_position < 0 || start_position > edl_length )
639 start_position = edl_length;
642 else if( get_cursor() != RIGHT_CURSOR )
643 set_cursor(RIGHT_CURSOR, 0, 1);
647 else if( get_button_down() && get_buttonpress() == 3 &&
648 x >= x1 && x < x2 ) {
650 current_operation = TIMEBAR_DRAG_CENTER;
651 starting_start_position = get_edl()->local_session->preview_start;
652 starting_end_position = get_edl()->local_session->preview_end;
653 if( starting_end_position < 0 || starting_end_position > edl_length )
654 starting_end_position = edl_length;
657 if( get_cursor() != HSEPARATE_CURSOR )
658 set_cursor(HSEPARATE_CURSOR, 0, 1);
663 if( !result && get_cursor() != ARROW_CURSOR )
664 set_cursor(ARROW_CURSOR, 0, 1);
670 int TimeBar::move_preview(int &redraw)
672 int result = 0, x = get_relative_cursor_x();
673 switch( current_operation ) {
674 case TIMEBAR_DRAG_LEFT: {
675 get_edl()->local_session->preview_start =
676 start_position + time_per_pixel * (x - start_cursor_x);
677 double preview_end = get_edl()->local_session->preview_end;
678 if( preview_end < 0 || preview_end > edl_length )
679 preview_end = get_edl()->local_session->preview_end = edl_length;
680 CLAMP(get_edl()->local_session->preview_start, 0, preview_end);
683 case TIMEBAR_DRAG_RIGHT: {
684 double preview_end = get_edl()->local_session->preview_end =
685 start_position + time_per_pixel * (x - start_cursor_x);
686 double preview_start = get_edl()->local_session->preview_start;
687 if( preview_end >= edl_length && !preview_start ) {
688 get_edl()->local_session->preview_end = -1;
689 if( preview_start > preview_end )
690 preview_start = get_edl()->local_session->preview_start = preview_end;
693 CLAMP(get_edl()->local_session->preview_end, preview_start, edl_length);
696 case TIMEBAR_DRAG_CENTER: {
697 double dt = time_per_pixel * (x - start_cursor_x);
698 get_edl()->local_session->preview_start = starting_start_position + dt;
699 get_edl()->local_session->preview_end = starting_end_position + dt;
700 if( get_edl()->local_session->preview_start < 0 ) {
701 get_edl()->local_session->preview_end -= get_edl()->local_session->preview_start;
702 get_edl()->local_session->preview_start = 0;
705 if( get_edl()->local_session->preview_end > edl_length ) {
706 get_edl()->local_session->preview_start -= get_edl()->local_session->preview_end - edl_length;
707 get_edl()->local_session->preview_end = edl_length;
713 //printf("TimeBar::move_preview %d %d\n", __LINE__, current_operation);
719 //printf("TimeBar::move_preview %d %d\n", __LINE__, current_operation);
724 void TimeBar::update_preview()
728 int TimeBar::samplemovement()
733 void TimeBar::stop_playback()
737 int TimeBar::button_press_event()
740 if( is_event_win() && cursor_above() ) {
741 if( has_preview() && get_buttonpress() == 3 ) {
742 result = test_preview(1);
744 // Change time format
745 else if( !is_vwindow() && ctrl_down() ) {
746 if( get_buttonpress() == 1 )
747 mwindow->next_time_format();
749 if( get_buttonpress() == 2 )
750 mwindow->prev_time_format();
753 else if( get_buttonpress() == 1 ) {
756 // Select region between two labels
757 if( !is_vwindow() && get_double_click() ) {
758 int x = get_relative_cursor_x();
759 double position = pixel_to_position(x);
761 select_region(position);
765 // Reposition highlight cursor
767 current_operation = TIMEBAR_DRAG;
776 void TimeBar::activate_timeline()
778 mwindow->gui->activate_timeline();
781 int TimeBar::cursor_motion_event()
786 switch( current_operation ) {
787 case TIMEBAR_DRAG_LEFT:
788 case TIMEBAR_DRAG_RIGHT:
789 case TIMEBAR_DRAG_CENTER:
791 result = move_preview(redraw);
794 case TIMEBAR_DRAG_LABEL:
796 EDL *edl = get_edl();
797 int pixel = get_relative_cursor_x();
798 double position = pixel_to_position(pixel);
799 if( drag_label->label )
800 drag_label->label->position = position;
801 else if( drag_label == in_point ) {
802 if( out_point && edl->local_session->outpoint_valid() ) {
803 double out_pos = edl->local_session->get_outpoint();
804 if( position > out_pos ) {
805 edl->local_session->set_outpoint(position);
806 drag_label = out_point;
810 edl->local_session->set_inpoint(position);
812 else if( drag_label == out_point ) {
813 if( in_point && edl->local_session->inpoint_valid() ) {
814 double in_pos = edl->local_session->get_inpoint();
815 if( position < in_pos ) {
816 edl->local_session->set_inpoint(position);
817 drag_label = in_point;
821 edl->local_session->set_outpoint(position);
827 handle_mwindow_drag();
833 result = test_preview(0);
845 int TimeBar::cursor_leave_event()
854 int TimeBar::button_release_event()
856 //printf("TimeBar::button_release_event %d %d\n", __LINE__, current_operation);
859 switch( current_operation )
862 mwindow->gui->get_focused_pane()->canvas->stop_dragscroll();
863 current_operation = TIMEBAR_NONE;
869 if( current_operation != TIMEBAR_NONE ) {
870 current_operation = TIMEBAR_NONE;
876 if( (!cursor_above() && highlighted) || need_redraw ) {
884 // Update the selection cursor during a dragging operation
885 void TimeBar::update_cursor()
889 void TimeBar::handle_mwindow_drag()
893 int TimeBar::select_region(double position)
895 Label *start = 0, *end = 0, *current;
896 for( current = get_edl()->labels->first; current; current = NEXT ) {
897 if( current->position > position ) {
903 for( current = get_edl()->labels->last ; current; current = PREVIOUS ) {
904 if( current->position <= position ) {
913 get_edl()->local_session->set_selectionstart(0);
915 get_edl()->local_session->set_selectionstart(start->position);
918 get_edl()->local_session->set_selectionend(get_edl()->tracks->total_length());
920 get_edl()->local_session->set_selectionend(end->position);
924 get_edl()->local_session->set_selectionstart(start->position);
925 get_edl()->local_session->set_selectionend(start->position);
929 mwindow->cwindow->gui->lock_window("TimeBar::select_region");
930 mwindow->cwindow->update(1, 0, 0);
931 mwindow->cwindow->gui->unlock_window();
932 mwindow->gui->lock_window("TimeBar::select_region");
933 mwindow->gui->hide_cursor(0);
934 mwindow->gui->draw_cursor(1);
935 mwindow->gui->flash_canvas(0);
936 mwindow->gui->activate_timeline();
937 mwindow->gui->zoombar->update();
938 mwindow->gui->unlock_window();
946 int TimeBar::delete_arrows()
951 double TimeBar::test_highlight()