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 = new LabelGUI(mwindow, this,
281 pixel, LabelGUI::get_y(mwindow, this),
283 new_label->set_cursor(INHERIT_CURSOR, 0, 0);
284 new_label->set_tooltip(current->textstr);
285 new_label->label = current;
286 labels.append(new_label);
288 // Reposition old label
290 LabelGUI *gui = labels.values[output];
291 if( gui->pixel != pixel ) {
296 // gui->draw_face(1,0);
299 labels.values[output]->position = current->position;
300 labels.values[output]->set_tooltip(current->textstr);
301 labels.values[output]->label = current;
304 labels.values[output++]->update_value();
309 // Delete excess labels
310 while(labels.total > output)
312 labels.remove_object();
315 // Get the labels to show
319 void TimeBar::update_highlights()
321 EDL *edl = get_edl();
323 for( int i = 0; i < labels.total; i++ ) {
324 labels.values[i]->update_value();
327 if( edl->equivalent(edl->local_session->get_inpoint(),
328 edl->local_session->get_selectionstart(1)) ||
329 edl->equivalent(edl->local_session->get_inpoint(),
330 edl->local_session->get_selectionend(1)) ) {
331 if( in_point ) in_point->update(1);
334 if( in_point ) in_point->update(0);
336 if( edl->equivalent(edl->local_session->get_outpoint(),
337 edl->local_session->get_selectionstart(1)) ||
338 edl->equivalent(edl->local_session->get_outpoint(),
339 edl->local_session->get_selectionend(1)) ) {
340 if( out_point ) out_point->update(1);
343 if( out_point ) out_point->update(0);
345 draw_inout_highlight();
348 void TimeBar::draw_inout_highlight()
350 EDL *edl = get_edl();
351 if( !edl->local_session->inpoint_valid() ) return;
352 if( !edl->local_session->outpoint_valid() ) return;
353 double in_position = edl->local_session->get_inpoint();
354 double out_position = edl->local_session->get_outpoint();
355 if( in_position >= out_position ) return;
356 int in_x = position_to_pixel(in_position);
357 int out_x = position_to_pixel(out_position);
358 CLAMP(in_x, 0, get_w());
359 CLAMP(out_x, 0, get_w());
360 set_color(mwindow->theme->inout_highlight_color);
364 draw_line(in_x, get_h()-2*lw, out_x, get_h()-2*lw);
369 void TimeBar::update_points()
371 EDL *edl = get_edl();
372 int64_t pixel = !edl ? 0 :
373 position_to_pixel(edl->local_session->get_inpoint());
376 if( edl && edl->local_session->inpoint_valid() &&
377 pixel >= 0 && pixel < get_w() ) {
378 if( !EQUIV(edl->local_session->get_inpoint(), in_point->position) ||
379 in_point->pixel != pixel ) {
380 in_point->pixel = pixel;
381 in_point->position = edl->local_session->get_inpoint();
382 in_point->reposition(0);
385 in_point->draw_face(1, 0);
394 if( edl && edl->local_session->inpoint_valid() &&
395 pixel >= 0 && pixel < get_w() ) {
396 add_subwindow(in_point = new InPointGUI(mwindow,
397 this, pixel, edl->local_session->get_inpoint()));
398 in_point->set_cursor(ARROW_CURSOR, 0, 0);
402 position_to_pixel(edl->local_session->get_outpoint());
405 if( edl && edl->local_session->outpoint_valid() &&
406 pixel >= 0 && pixel < get_w()) {
407 if( !EQUIV(edl->local_session->get_outpoint(), out_point->position) ||
408 out_point->pixel != pixel ) {
409 out_point->pixel = pixel;
410 out_point->position = edl->local_session->get_outpoint();
411 out_point->reposition(0);
414 out_point->draw_face(1, 0);
423 if( edl && edl->local_session->outpoint_valid() &&
424 pixel >= 0 && pixel < get_w() ) {
425 add_subwindow(out_point = new OutPointGUI(mwindow,
426 this, pixel, edl->local_session->get_outpoint()));
427 out_point->set_cursor(ARROW_CURSOR, 0, 0);
433 void TimeBar::update_clock(double position)
437 void TimeBar::update(int flush)
440 // Need to redo these when range is drawn to get the background updated.
445 EDL *edl = get_edl();
447 int x = get_relative_cursor_x();
448 // Draw highlight position
449 if( edl && (highlighted || current_operation == TIMEBAR_DRAG) &&
450 x >= 0 && x < get_w() ) {
451 //printf("TimeBar::update %d %d\n", __LINE__, x);
452 double position = pixel_to_position(x);
454 position = mwindow->edl->align_to_frame(position, 0);
455 pixel = position_to_pixel(position);
456 update_clock(position);
460 double position = test_highlight();
461 if( position >= 0 ) pixel = position_to_pixel(position);
465 if( pixel >= 0 && pixel < get_w() ) {
466 set_color(mwindow->theme->timebar_cursor_color);
468 //printf("TimeBar::update %d pane=%d pixel=%jd\n", __LINE__, pane->number, pixel);
469 draw_line(pixel, 0, pixel, get_h());
475 double playback_start = edl->local_session->playback_start;
476 if( playback_start >= 0 ) {
477 int64_t pixel = position_to_pixel(playback_start);
478 set_color(mwindow->theme->timebar_cursor_color ^ 0x0000ff);
479 draw_line(pixel, 0, pixel, get_h());
480 double playback_end = edl->local_session->playback_end;
481 if( playback_end > playback_start ) {
482 pixel = position_to_pixel(playback_end);
483 set_color(mwindow->theme->timebar_cursor_color ^ 0x00ff00);
484 draw_line(pixel, 0, pixel, get_h());
488 double position = edl->local_session->get_selectionstart(1);
489 int64_t pixel = position_to_pixel(position);
490 // Draw insertion point position.
491 int color = mwindow->theme->timebar_cursor_color;
492 if( mwindow->preferences->forward_render_displacement )
495 draw_line(pixel, 0, pixel, get_h());
500 // Get the labels to show
503 //printf("TimeBar::update %d this=%p %d\n", __LINE__, this, current_operation);
508 int TimeBar::delete_project()
510 // labels->delete_all();
514 int TimeBar::save(FileXML *xml)
516 // labels->save(xml);
523 void TimeBar::draw_time()
527 EDL* TimeBar::get_edl()
534 void TimeBar::draw_range()
536 //printf("TimeBar::draw_range %d %p\n", __LINE__, get_edl());
537 if( has_preview() && get_edl() ) {
539 get_preview_pixels(x1, x2);
540 draw_3segmenth(0, 0, x1, mwindow->theme->timebar_view_data);
541 draw_top_background(get_parent(), x1, 0, x2 - x1, get_h());
542 draw_3segmenth(x2, 0, get_w() - x2, mwindow->theme->timebar_view_data);
545 draw_line(x1, 0, x1, get_h());
546 draw_line(x2, 0, x2, get_h());
549 EDL *edl = get_edl();
551 int64_t pixel = position_to_pixel(
552 edl->local_session->get_selectionstart(1));
553 // Draw insertion point position if this timebar belongs to a window which
554 // has something other than the master EDL.
555 set_color(mwindow->theme->timebar_cursor_color);
556 draw_line(pixel, 0, pixel, get_h());
560 draw_top_background(get_parent(), 0, 0, get_w(), get_h());
563 void TimeBar::select_label(double position)
574 double TimeBar::get_edl_length()
576 edl_length = get_edl() ? get_edl()->tracks->total_length() : 0;
578 time_per_pixel = !EQUIV(edl_length, 0) ? edl_length/w1 : w1;
582 int TimeBar::get_preview_pixels(int &x1, int &x2)
584 x1 = 0; x2 = get_w();
586 EDL *edl = get_edl();
587 if( edl && !EQUIV(edl_length, 0) ) {
588 double preview_start = edl->local_session->preview_start;
589 double preview_end = edl->local_session->preview_end;
590 if( preview_end < 0 || preview_end > edl_length )
591 preview_end = edl_length;
592 if( preview_end >= preview_start ) {
593 x1 = (int)(preview_start / time_per_pixel);
594 x2 = (int)(preview_end / time_per_pixel);
601 int TimeBar::test_preview(int buttonpress)
606 if( get_edl() && cursor_inside() && buttonpress >= 0 ) {
607 int x1, x2, x = get_relative_cursor_x();
608 get_preview_pixels(x1, x2);
609 //printf("TimeBar::test_preview %d %d %d\n", x1, x2, x);
610 // Inside left handle
611 if( x >= x1 - HANDLE_W && x < x1 + HANDLE_W &&
612 // Ignore left handle if both handles are up against the left side
615 current_operation = TIMEBAR_DRAG_LEFT;
616 start_position = get_edl()->local_session->preview_start;
619 else if( get_cursor() != LEFT_CURSOR )
620 set_cursor(LEFT_CURSOR, 0, 1);
623 // Inside right handle
624 else if( x >= x2 - HANDLE_W && x < x2 + HANDLE_W &&
625 // Ignore right handle if both handles are up against the right side
626 x1 < get_w() - HANDLE_W ) {
628 current_operation = TIMEBAR_DRAG_RIGHT;
629 start_position = get_edl()->local_session->preview_end;
630 if( start_position < 0 || start_position > edl_length )
631 start_position = edl_length;
634 else if( get_cursor() != RIGHT_CURSOR )
635 set_cursor(RIGHT_CURSOR, 0, 1);
639 else if( get_button_down() && get_buttonpress() == 3 &&
640 x >= x1 && x < x2 ) {
642 current_operation = TIMEBAR_DRAG_CENTER;
643 starting_start_position = get_edl()->local_session->preview_start;
644 starting_end_position = get_edl()->local_session->preview_end;
645 if( starting_end_position < 0 || starting_end_position > edl_length )
646 starting_end_position = edl_length;
649 if( get_cursor() != HSEPARATE_CURSOR )
650 set_cursor(HSEPARATE_CURSOR, 0, 1);
655 if( !result && get_cursor() != ARROW_CURSOR )
656 set_cursor(ARROW_CURSOR, 0, 1);
662 int TimeBar::move_preview(int &redraw)
664 int result = 0, x = get_relative_cursor_x();
665 switch( current_operation ) {
666 case TIMEBAR_DRAG_LEFT: {
667 get_edl()->local_session->preview_start =
668 start_position + time_per_pixel * (x - start_cursor_x);
669 double preview_end = get_edl()->local_session->preview_end;
670 if( preview_end < 0 || preview_end > edl_length )
671 preview_end = get_edl()->local_session->preview_end = edl_length;
672 CLAMP(get_edl()->local_session->preview_start, 0, preview_end);
675 case TIMEBAR_DRAG_RIGHT: {
676 double preview_end = get_edl()->local_session->preview_end =
677 start_position + time_per_pixel * (x - start_cursor_x);
678 double preview_start = get_edl()->local_session->preview_start;
679 if( preview_end >= edl_length && !preview_start ) {
680 get_edl()->local_session->preview_end = -1;
681 if( preview_start > preview_end )
682 preview_start = get_edl()->local_session->preview_start = preview_end;
685 CLAMP(get_edl()->local_session->preview_end, preview_start, edl_length);
688 case TIMEBAR_DRAG_CENTER: {
689 double dt = time_per_pixel * (x - start_cursor_x);
690 get_edl()->local_session->preview_start = starting_start_position + dt;
691 get_edl()->local_session->preview_end = starting_end_position + dt;
692 if( get_edl()->local_session->preview_start < 0 ) {
693 get_edl()->local_session->preview_end -= get_edl()->local_session->preview_start;
694 get_edl()->local_session->preview_start = 0;
697 if( get_edl()->local_session->preview_end > edl_length ) {
698 get_edl()->local_session->preview_start -= get_edl()->local_session->preview_end - edl_length;
699 get_edl()->local_session->preview_end = edl_length;
705 //printf("TimeBar::move_preview %d %d\n", __LINE__, current_operation);
711 //printf("TimeBar::move_preview %d %d\n", __LINE__, current_operation);
716 void TimeBar::update_preview()
720 int TimeBar::samplemovement()
725 void TimeBar::stop_playback()
729 int TimeBar::button_press_event()
732 if( is_event_win() && cursor_above() ) {
733 if( has_preview() && get_buttonpress() == 3 ) {
734 result = test_preview(1);
736 // Change time format
737 else if( !is_vwindow() && ctrl_down() ) {
738 if( get_buttonpress() == 1 )
739 mwindow->next_time_format();
741 if( get_buttonpress() == 2 )
742 mwindow->prev_time_format();
745 else if( get_buttonpress() == 1 ) {
748 // Select region between two labels
749 if( !is_vwindow() && get_double_click() &&
750 get_edl()->labels->first ) {
751 int x = get_relative_cursor_x();
752 double position = pixel_to_position(x);
754 select_region(position);
758 // Reposition highlight cursor
760 current_operation = TIMEBAR_DRAG;
769 void TimeBar::activate_timeline()
771 mwindow->gui->activate_timeline();
774 int TimeBar::cursor_motion_event()
779 switch( current_operation ) {
780 case TIMEBAR_DRAG_LEFT:
781 case TIMEBAR_DRAG_RIGHT:
782 case TIMEBAR_DRAG_CENTER:
784 result = move_preview(redraw);
787 case TIMEBAR_DRAG_LABEL:
789 EDL *edl = get_edl();
790 int pixel = get_relative_cursor_x();
791 double position = pixel_to_position(pixel);
792 if( drag_label->label )
793 drag_label->label->position = position;
794 else if( drag_label == in_point ) {
795 if( out_point && edl->local_session->outpoint_valid() ) {
796 double out_pos = edl->local_session->get_outpoint();
797 if( position > out_pos ) {
798 edl->local_session->set_outpoint(position);
799 drag_label = out_point;
803 edl->local_session->set_inpoint(position);
805 else if( drag_label == out_point ) {
806 if( in_point && edl->local_session->inpoint_valid() ) {
807 double in_pos = edl->local_session->get_inpoint();
808 if( position < in_pos ) {
809 edl->local_session->set_inpoint(position);
810 drag_label = in_point;
814 edl->local_session->set_outpoint(position);
820 handle_mwindow_drag();
826 result = test_preview(0);
838 int TimeBar::cursor_leave_event()
847 int TimeBar::button_release_event()
849 //printf("TimeBar::button_release_event %d %d\n", __LINE__, current_operation);
852 switch( current_operation )
855 mwindow->gui->get_focused_pane()->canvas->stop_dragscroll();
856 current_operation = TIMEBAR_NONE;
862 if( current_operation != TIMEBAR_NONE ) {
863 current_operation = TIMEBAR_NONE;
869 if( (!cursor_above() && highlighted) || need_redraw ) {
877 // Update the selection cursor during a dragging operation
878 void TimeBar::update_cursor()
882 void TimeBar::handle_mwindow_drag()
886 int TimeBar::select_region(double position)
888 Label *start = 0, *end = 0, *current;
889 for( current = get_edl()->labels->first; current; current = NEXT ) {
890 if( current->position > position ) {
896 for( current = get_edl()->labels->last ; current; current = PREVIOUS ) {
897 if( current->position <= position ) {
906 get_edl()->local_session->set_selectionstart(0);
908 get_edl()->local_session->set_selectionstart(start->position);
911 get_edl()->local_session->set_selectionend(get_edl()->tracks->total_length());
913 get_edl()->local_session->set_selectionend(end->position);
917 get_edl()->local_session->set_selectionstart(start->position);
918 get_edl()->local_session->set_selectionend(start->position);
923 mwindow->cwindow->update(1, 0, 0);
924 mwindow->gui->lock_window("TimeBar::select_region 3");
925 mwindow->gui->hide_cursor(0);
926 mwindow->gui->draw_cursor(1);
927 mwindow->gui->flash_canvas(0);
928 mwindow->gui->activate_timeline();
929 mwindow->gui->zoombar->update();
930 mwindow->gui->unlock_window();
931 lock_window("TimeBar::select_region 4");
937 int TimeBar::delete_arrows()
942 double TimeBar::test_highlight()