4 * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
5 * Copyright (C) 2003-2016 Cinelerra CV contributors
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "awindowgui.h"
25 #include "bcsignals.h"
27 #include "cplayback.h"
30 #include "cwindowgui.h"
32 #include "edlsession.h"
36 #include "labeledit.h"
37 #include "localsession.h"
38 #include "maincursor.h"
42 #include "mwindowgui.h"
44 #include "preferences.h"
45 #include "recordlabel.h"
46 #include "localsession.h"
47 #include "mainsession.h"
50 #include "timelinepane.h"
51 #include "trackcanvas.h"
53 #include "transportque.h"
57 #include "vwindowgui.h"
61 LabelGUI::LabelGUI(MWindow *mwindow, TimeBar *timebar,
63 double position, VFrame **data)
64 : BC_Toggle(translate_pixel(mwindow, pixel), y,
65 data ? data : mwindow->theme->label_toggle, 0)
67 this->mwindow = mwindow;
68 this->timebar = timebar;
71 this->position = position;
77 if( timebar->drag_label == this )
78 timebar->drag_label = 0;
81 int LabelGUI::get_y(MWindow *mwindow, TimeBar *timebar)
83 return timebar->get_h() -
84 mwindow->theme->label_toggle[0]->get_h();
87 int LabelGUI::translate_pixel(MWindow *mwindow, int pixel)
89 int result = pixel - mwindow->theme->label_toggle[0]->get_w() / 2;
93 void LabelGUI::reposition(int flush)
95 reposition_window(translate_pixel(mwindow, pixel),
99 int LabelGUI::button_press_event()
101 int result = test_drag_label(1);
103 if( this->is_event_win() && get_buttonpress() == 3 ) {
106 get_abs_cursor(cur_x, cur_y, 0);
107 timebar->label_edit->start(label, cur_x, cur_y);
111 result = BC_Toggle::button_press_event();
114 set_tooltip(this->label->textstr);
118 int LabelGUI::button_release_event()
120 int ret = BC_Toggle::button_release_event();
125 int LabelGUI::test_drag_label(int press)
127 if( is_event_win() && get_buttonpress() == 1 ) {
128 switch( timebar->current_operation ) {
130 if( press && get_value() ) {
131 timebar->current_operation = TIMEBAR_DRAG_LABEL;
132 timebar->drag_label = this;
133 set_cursor(HSEPARATE_CURSOR, 0, 0);
134 mwindow->undo->update_undo_before(_("drag label"), this);
138 case TIMEBAR_DRAG_LABEL:
140 timebar->current_operation = TIMEBAR_NONE;
141 timebar->drag_label = 0;
142 set_cursor(ARROW_CURSOR, 0, 0);
143 mwindow->undo->update_undo_after(_("drag label"), LOAD_TIMEBAR);
144 mwindow->awindow->gui->async_update_assets(); // labels folder
152 int LabelGUI::handle_event()
154 timebar->select_label(position);
158 void LabelGUI::update_value()
160 EDL *edl = timebar->get_edl();
161 double start = edl->local_session->get_selectionstart(1);
162 double end = edl->local_session->get_selectionend(1);
163 int v = ( label->position >= start && end >= label->position ) ||
164 edl->equivalent(label->position, start) ||
165 edl->equivalent(label->position, end) ||
166 timebar->drag_label == this ? 1 : 0;
171 InPointGUI::InPointGUI(MWindow *mwindow, TimeBar *timebar,
172 int64_t pixel, double position)
173 : LabelGUI(mwindow, timebar,
174 pixel, get_y(mwindow, timebar),
175 position, mwindow->theme->in_point)
177 //printf("InPointGUI::InPointGUI %d %d\n", pixel, get_y(mwindow, timebar));
179 InPointGUI::~InPointGUI()
182 int InPointGUI::get_y(MWindow *mwindow, TimeBar *timebar)
185 result = timebar->get_h() -
186 mwindow->theme->in_point[0]->get_h();
191 OutPointGUI::OutPointGUI(MWindow *mwindow, TimeBar *timebar,
192 int64_t pixel, double position)
193 : LabelGUI(mwindow, timebar,
194 pixel, get_y(mwindow, timebar),
195 position, mwindow->theme->out_point)
197 //printf("OutPointGUI::OutPointGUI %d %d\n", pixel, get_y(mwindow, timebar));
199 OutPointGUI::~OutPointGUI()
202 int OutPointGUI::get_y(MWindow *mwindow, TimeBar *timebar)
204 return timebar->get_h() -
205 mwindow->theme->out_point[0]->get_h();
209 PresentationGUI::PresentationGUI(MWindow *mwindow, TimeBar *timebar,
210 int64_t pixel, double position)
211 : LabelGUI(mwindow, timebar, pixel, get_y(mwindow, timebar), position)
214 PresentationGUI::~PresentationGUI()
218 TimeBar::TimeBar(MWindow *mwindow, BC_WindowBase *gui,
219 int x, int y, int w, int h)
220 : BC_SubWindow(x, y, w, h)
222 //printf("TimeBar::TimeBar %d %d %d %d\n", x, y, w, h);
224 this->mwindow = mwindow;
225 this->drag_label = 0;
226 label_edit = new LabelEdit(mwindow, mwindow->awindow, 0);
236 labels.remove_all_objects();
237 presentations.remove_all_objects();
240 void TimeBar::create_objects()
244 //printf("TimeBar::create_objects %d\n", __LINE__);
245 current_operation = TIMEBAR_NONE;
246 set_cursor(UPRIGHT_ARROW_CURSOR, 0, 0);
251 int64_t TimeBar::position_to_pixel(double position)
254 return (int64_t)(position / time_per_pixel);
258 double TimeBar::pixel_to_position(int pixel)
261 pixel += get_edl()->local_session->view_start[pane->number];
264 return (double)pixel *
265 get_edl()->local_session->zoom_sample /
266 get_edl()->session->sample_rate;
269 void TimeBar::update_labels()
272 EDL *edl = get_edl();
275 for( Label *current=edl->labels->first; current; current=NEXT ) {
276 int64_t pixel = position_to_pixel(current->position);
277 if( pixel >= 0 && pixel < get_w() ) {
279 if( output >= labels.total ) {
281 add_subwindow(new_label = new LabelGUI(mwindow, this,
282 pixel, LabelGUI::get_y(mwindow, this),
284 new_label->set_cursor(INHERIT_CURSOR, 0, 0);
285 new_label->set_tooltip(current->textstr);
286 new_label->label = current;
287 labels.append(new_label);
289 // Reposition old label
291 LabelGUI *gui = labels.values[output];
292 if( gui->pixel != pixel ) {
297 // gui->draw_face(1,0);
300 labels.values[output]->position = current->position;
301 labels.values[output]->set_tooltip(current->textstr);
302 labels.values[output]->label = current;
305 labels.values[output++]->update_value();
310 // Delete excess labels
311 while(labels.total > output)
313 labels.remove_object();
316 // Get the labels to show
320 void TimeBar::update_highlights()
322 EDL *edl = get_edl();
324 for( int i = 0; i < labels.total; i++ ) {
325 labels.values[i]->update_value();
328 if( edl->equivalent(edl->local_session->get_inpoint(),
329 edl->local_session->get_selectionstart(1)) ||
330 edl->equivalent(edl->local_session->get_inpoint(),
331 edl->local_session->get_selectionend(1)) ) {
332 if( in_point ) in_point->update(1);
335 if( in_point ) in_point->update(0);
337 if( edl->equivalent(edl->local_session->get_outpoint(),
338 edl->local_session->get_selectionstart(1)) ||
339 edl->equivalent(edl->local_session->get_outpoint(),
340 edl->local_session->get_selectionend(1)) ) {
341 if( out_point ) out_point->update(1);
344 if( out_point ) out_point->update(0);
346 draw_inout_highlight();
349 void TimeBar::draw_inout_highlight()
351 EDL *edl = get_edl();
352 if( !edl->local_session->inpoint_valid() ) return;
353 if( !edl->local_session->outpoint_valid() ) return;
354 double in_position = edl->local_session->get_inpoint();
355 double out_position = edl->local_session->get_outpoint();
356 if( in_position >= out_position ) return;
357 int in_x = position_to_pixel(in_position);
358 int out_x = position_to_pixel(out_position);
359 CLAMP(in_x, 0, get_w());
360 CLAMP(out_x, 0, get_w());
361 set_color(mwindow->theme->inout_highlight_color);
365 draw_line(in_x, get_h()-2*lw, out_x, get_h()-2*lw);
370 void TimeBar::update_points()
372 EDL *edl = get_edl();
373 int64_t pixel = !edl ? 0 :
374 position_to_pixel(edl->local_session->get_inpoint());
377 if( edl && edl->local_session->inpoint_valid() &&
378 pixel >= 0 && pixel < get_w() ) {
379 if( !EQUIV(edl->local_session->get_inpoint(), in_point->position) ||
380 in_point->pixel != pixel ) {
381 in_point->pixel = pixel;
382 in_point->position = edl->local_session->get_inpoint();
383 in_point->reposition(0);
386 in_point->draw_face(1, 0);
395 if( edl && edl->local_session->inpoint_valid() &&
396 pixel >= 0 && pixel < get_w() ) {
397 add_subwindow(in_point = new InPointGUI(mwindow,
398 this, pixel, edl->local_session->get_inpoint()));
399 in_point->set_cursor(ARROW_CURSOR, 0, 0);
403 position_to_pixel(edl->local_session->get_outpoint());
406 if( edl && edl->local_session->outpoint_valid() &&
407 pixel >= 0 && pixel < get_w()) {
408 if( !EQUIV(edl->local_session->get_outpoint(), out_point->position) ||
409 out_point->pixel != pixel ) {
410 out_point->pixel = pixel;
411 out_point->position = edl->local_session->get_outpoint();
412 out_point->reposition(0);
415 out_point->draw_face(1, 0);
424 if( edl && edl->local_session->outpoint_valid() &&
425 pixel >= 0 && pixel < get_w() ) {
426 add_subwindow(out_point = new OutPointGUI(mwindow,
427 this, pixel, edl->local_session->get_outpoint()));
428 out_point->set_cursor(ARROW_CURSOR, 0, 0);
434 void TimeBar::update_clock(double position)
438 void TimeBar::update(int flush)
441 // Need to redo these when range is drawn to get the background updated.
446 EDL *edl = get_edl();
448 int x = get_relative_cursor_x();
449 // Draw highlight position
450 if( edl && (highlighted || current_operation == TIMEBAR_DRAG) &&
451 x >= 0 && x < get_w() ) {
452 //printf("TimeBar::update %d %d\n", __LINE__, x);
453 double position = pixel_to_position(x);
455 position = mwindow->edl->align_to_frame(position, 0);
456 pixel = position_to_pixel(position);
457 update_clock(position);
461 double position = test_highlight();
462 if( position >= 0 ) pixel = position_to_pixel(position);
466 if( pixel >= 0 && pixel < get_w() ) {
467 set_color(mwindow->theme->timebar_cursor_color);
469 //printf("TimeBar::update %d pane=%d pixel=%jd\n", __LINE__, pane->number, pixel);
470 draw_line(pixel, 0, pixel, get_h());
476 double playback_start = edl->local_session->playback_start;
477 if( playback_start >= 0 ) {
478 int64_t pixel = position_to_pixel(playback_start);
479 set_color(mwindow->theme->timebar_cursor_color ^ 0x0000ff);
480 draw_line(pixel, 0, pixel, get_h());
481 double playback_end = edl->local_session->playback_end;
482 if( playback_end > playback_start ) {
483 pixel = position_to_pixel(playback_end);
484 set_color(mwindow->theme->timebar_cursor_color ^ 0x00ff00);
485 draw_line(pixel, 0, pixel, get_h());
489 double position = edl->local_session->get_selectionstart(1);
490 int64_t pixel = position_to_pixel(position);
491 // Draw insertion point position.
492 int color = mwindow->theme->timebar_cursor_color;
493 if( mwindow->preferences->forward_render_displacement )
496 draw_line(pixel, 0, pixel, get_h());
501 // Get the labels to show
504 //printf("TimeBar::update %d this=%p %d\n", __LINE__, this, current_operation);
509 int TimeBar::delete_project()
511 // labels->delete_all();
515 int TimeBar::save(FileXML *xml)
517 // labels->save(xml);
524 void TimeBar::draw_time()
528 EDL* TimeBar::get_edl()
535 void TimeBar::draw_range()
537 //printf("TimeBar::draw_range %d %p\n", __LINE__, get_edl());
538 if( has_preview() && get_edl() ) {
540 get_preview_pixels(x1, x2);
541 draw_3segmenth(0, 0, x1, mwindow->theme->timebar_view_data);
542 draw_top_background(get_parent(), x1, 0, x2 - x1, get_h());
543 draw_3segmenth(x2, 0, get_w() - x2, mwindow->theme->timebar_view_data);
546 draw_line(x1, 0, x1, get_h());
547 draw_line(x2, 0, x2, get_h());
550 EDL *edl = get_edl();
552 int64_t pixel = position_to_pixel(
553 edl->local_session->get_selectionstart(1));
554 // Draw insertion point position if this timebar belongs to a window which
555 // has something other than the master EDL.
556 set_color(mwindow->theme->timebar_cursor_color);
557 draw_line(pixel, 0, pixel, get_h());
561 draw_top_background(get_parent(), 0, 0, get_w(), get_h());
564 void TimeBar::select_label(double position)
575 double TimeBar::get_edl_length()
577 edl_length = get_edl() ? get_edl()->tracks->total_length() : 0;
579 time_per_pixel = !EQUIV(edl_length, 0) ? edl_length/w1 : w1;
583 int TimeBar::get_preview_pixels(int &x1, int &x2)
585 x1 = 0; x2 = get_w();
587 EDL *edl = get_edl();
588 if( edl && !EQUIV(edl_length, 0) ) {
589 double preview_start = edl->local_session->preview_start;
590 double preview_end = edl->local_session->preview_end;
591 if( preview_end < 0 || preview_end > edl_length )
592 preview_end = edl_length;
593 if( preview_end >= preview_start ) {
594 x1 = (int)(preview_start / time_per_pixel);
595 x2 = (int)(preview_end / time_per_pixel);
602 int TimeBar::test_preview(int buttonpress)
607 if( get_edl() && cursor_inside() && buttonpress >= 0 ) {
608 int x1, x2, x = get_relative_cursor_x();
609 get_preview_pixels(x1, x2);
610 //printf("TimeBar::test_preview %d %d %d\n", x1, x2, x);
611 // Inside left handle
612 if( x >= x1 - HANDLE_W && x < x1 + HANDLE_W &&
613 // Ignore left handle if both handles are up against the left side
616 current_operation = TIMEBAR_DRAG_LEFT;
617 start_position = get_edl()->local_session->preview_start;
620 else if( get_cursor() != LEFT_CURSOR )
621 set_cursor(LEFT_CURSOR, 0, 1);
624 // Inside right handle
625 else if( x >= x2 - HANDLE_W && x < x2 + HANDLE_W &&
626 // Ignore right handle if both handles are up against the right side
627 x1 < get_w() - HANDLE_W ) {
629 current_operation = TIMEBAR_DRAG_RIGHT;
630 start_position = get_edl()->local_session->preview_end;
631 if( start_position < 0 || start_position > edl_length )
632 start_position = edl_length;
635 else if( get_cursor() != RIGHT_CURSOR )
636 set_cursor(RIGHT_CURSOR, 0, 1);
640 else if( get_button_down() && get_buttonpress() == 3 &&
641 x >= x1 && x < x2 ) {
643 current_operation = TIMEBAR_DRAG_CENTER;
644 starting_start_position = get_edl()->local_session->preview_start;
645 starting_end_position = get_edl()->local_session->preview_end;
646 if( starting_end_position < 0 || starting_end_position > edl_length )
647 starting_end_position = edl_length;
650 if( get_cursor() != HSEPARATE_CURSOR )
651 set_cursor(HSEPARATE_CURSOR, 0, 1);
656 if( !result && get_cursor() != ARROW_CURSOR )
657 set_cursor(ARROW_CURSOR, 0, 1);
663 int TimeBar::move_preview(int &redraw)
665 int result = 0, x = get_relative_cursor_x();
666 switch( current_operation ) {
667 case TIMEBAR_DRAG_LEFT: {
668 get_edl()->local_session->preview_start =
669 start_position + time_per_pixel * (x - start_cursor_x);
670 double preview_end = get_edl()->local_session->preview_end;
671 if( preview_end < 0 || preview_end > edl_length )
672 preview_end = get_edl()->local_session->preview_end = edl_length;
673 CLAMP(get_edl()->local_session->preview_start, 0, preview_end);
676 case TIMEBAR_DRAG_RIGHT: {
677 double preview_end = get_edl()->local_session->preview_end =
678 start_position + time_per_pixel * (x - start_cursor_x);
679 double preview_start = get_edl()->local_session->preview_start;
680 if( preview_end >= edl_length && !preview_start ) {
681 get_edl()->local_session->preview_end = -1;
682 if( preview_start > preview_end )
683 preview_start = get_edl()->local_session->preview_start = preview_end;
686 CLAMP(get_edl()->local_session->preview_end, preview_start, edl_length);
689 case TIMEBAR_DRAG_CENTER: {
690 double dt = time_per_pixel * (x - start_cursor_x);
691 get_edl()->local_session->preview_start = starting_start_position + dt;
692 get_edl()->local_session->preview_end = starting_end_position + dt;
693 if( get_edl()->local_session->preview_start < 0 ) {
694 get_edl()->local_session->preview_end -= get_edl()->local_session->preview_start;
695 get_edl()->local_session->preview_start = 0;
698 if( get_edl()->local_session->preview_end > edl_length ) {
699 get_edl()->local_session->preview_start -= get_edl()->local_session->preview_end - edl_length;
700 get_edl()->local_session->preview_end = edl_length;
706 //printf("TimeBar::move_preview %d %d\n", __LINE__, current_operation);
712 //printf("TimeBar::move_preview %d %d\n", __LINE__, current_operation);
717 void TimeBar::update_preview()
721 int TimeBar::samplemovement()
726 void TimeBar::stop_playback()
730 int TimeBar::button_press_event()
733 if( is_event_win() && cursor_above() ) {
734 if( has_preview() && get_buttonpress() == 3 ) {
735 result = test_preview(1);
737 // Change time format
738 else if( !is_vwindow() && ctrl_down() ) {
739 if( get_buttonpress() == 1 )
740 mwindow->next_time_format();
742 if( get_buttonpress() == 2 )
743 mwindow->prev_time_format();
746 else if( get_buttonpress() == 1 ) {
749 // Select region between two labels
750 if( !is_vwindow() && get_double_click() &&
751 get_edl()->labels->first ) {
752 int x = get_relative_cursor_x();
753 double position = pixel_to_position(x);
755 select_region(position);
759 // Reposition highlight cursor
761 current_operation = TIMEBAR_DRAG;
770 void TimeBar::activate_timeline()
772 mwindow->gui->activate_timeline();
775 int TimeBar::cursor_motion_event()
780 switch( current_operation ) {
781 case TIMEBAR_DRAG_LEFT:
782 case TIMEBAR_DRAG_RIGHT:
783 case TIMEBAR_DRAG_CENTER:
785 result = move_preview(redraw);
788 case TIMEBAR_DRAG_LABEL:
790 EDL *edl = get_edl();
791 int pixel = get_relative_cursor_x();
792 double position = pixel_to_position(pixel);
793 if( drag_label->label )
794 drag_label->label->position = position;
795 else if( drag_label == in_point ) {
796 if( out_point && edl->local_session->outpoint_valid() ) {
797 double out_pos = edl->local_session->get_outpoint();
798 if( position > out_pos ) {
799 edl->local_session->set_outpoint(position);
800 drag_label = out_point;
804 edl->local_session->set_inpoint(position);
806 else if( drag_label == out_point ) {
807 if( in_point && edl->local_session->inpoint_valid() ) {
808 double in_pos = edl->local_session->get_inpoint();
809 if( position < in_pos ) {
810 edl->local_session->set_inpoint(position);
811 drag_label = in_point;
815 edl->local_session->set_outpoint(position);
821 handle_mwindow_drag();
827 result = test_preview(0);
839 int TimeBar::cursor_leave_event()
848 int TimeBar::button_release_event()
850 //printf("TimeBar::button_release_event %d %d\n", __LINE__, current_operation);
853 switch( current_operation ) {
855 mwindow->gui->get_focused_pane()->canvas->stop_dragscroll();
856 current_operation = TIMEBAR_NONE;
858 CWindowCanvas *canvas = mwindow->cwindow->gui->canvas;
859 canvas->draw_scope(canvas->refresh_frame, -1);
863 if( current_operation != TIMEBAR_NONE ) {
864 current_operation = TIMEBAR_NONE;
870 if( (!cursor_above() && highlighted) || need_redraw ) {
878 // Update the selection cursor during a dragging operation
879 void TimeBar::update_cursor()
883 void TimeBar::handle_mwindow_drag()
887 int TimeBar::select_region(double position)
889 Label *start = 0, *end = 0, *current;
890 for( current = get_edl()->labels->first; current; current = NEXT ) {
891 if( current->position > position ) {
897 for( current = get_edl()->labels->last ; current; current = PREVIOUS ) {
898 if( current->position <= position ) {
907 get_edl()->local_session->set_selectionstart(0);
909 get_edl()->local_session->set_selectionstart(start->position);
912 get_edl()->local_session->set_selectionend(get_edl()->tracks->total_length());
914 get_edl()->local_session->set_selectionend(end->position);
918 get_edl()->local_session->set_selectionstart(start->position);
919 get_edl()->local_session->set_selectionend(start->position);
924 mwindow->cwindow->update(1, 0, 0);
925 mwindow->gui->lock_window("TimeBar::select_region 3");
926 mwindow->gui->hide_cursor(0);
927 mwindow->gui->draw_cursor(1);
928 mwindow->gui->flash_canvas(0);
929 mwindow->gui->activate_timeline();
930 mwindow->gui->zoombar->update();
931 mwindow->gui->unlock_window();
932 lock_window("TimeBar::select_region 4");
938 int TimeBar::delete_arrows()
943 double TimeBar::test_highlight()