Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / cinelerra / mtimebar.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "bcsignals.h"
23 #include "clip.h"
24 #include "cplayback.h"
25 #include "cwindow.h"
26 #include "edl.h"
27 #include "edlsession.h"
28 #include "localsession.h"
29 #include "mainclock.h"
30 #include "maincursor.h"
31 #include "mainsession.h"
32 #include "mbuttons.h"
33 #include "mtimebar.h"
34 #include "mwindowgui.h"
35 #include "mwindow.h"
36 #include "patchbay.h"
37 #include "preferences.h"
38 #include "theme.h"
39 #include "trackcanvas.h"
40 #include "tracks.h"
41 #include "transportque.h"
42 #include "zoombar.h"
43
44
45
46 MTimeBar::MTimeBar(MWindow *mwindow,
47         MWindowGUI *gui,
48         int x,
49         int y,
50         int w,
51         int h)
52  : TimeBar(mwindow, gui, x, y, w, h)
53 {
54         this->gui = gui;
55         this->pane = 0;
56 }
57
58 MTimeBar::MTimeBar(MWindow *mwindow,
59         TimelinePane *pane,
60         int x,
61         int y,
62         int w,
63         int h)
64  : TimeBar(mwindow, mwindow->gui, x, y, w, h)
65 {
66         this->gui = mwindow->gui;
67         this->pane = pane;
68 }
69
70 void MTimeBar::create_objects()
71 {
72         gui->add_subwindow(menu = new TimeBarPopup(mwindow));
73         menu->create_objects();
74
75         TimeBar::create_objects();
76 }
77
78
79 double MTimeBar::pixel_to_position(int pixel)
80 {
81         return (double)pixel *
82                 mwindow->edl->local_session->zoom_sample /
83                 mwindow->edl->session->sample_rate +
84                 (double)mwindow->edl->local_session->view_start[pane->number] *
85                 mwindow->edl->local_session->zoom_sample /
86                 mwindow->edl->session->sample_rate;
87 }
88
89
90 int64_t MTimeBar::position_to_pixel(double position)
91 {
92         return (int64_t)(position *
93                 mwindow->edl->session->sample_rate /
94                 mwindow->edl->local_session->zoom_sample -
95                 mwindow->edl->local_session->view_start[pane->number]);
96 }
97
98
99 void MTimeBar::stop_playback()
100 {
101         gui->unlock_window();
102         gui->mbuttons->transport->handle_transport(STOP, 1, 0, 0);
103         gui->lock_window();
104 }
105
106 #define TEXT_MARGIN 4
107 #define TICK_SPACING 5
108 #define LINE_MARGIN 3
109 #define TICK_MARGIN 16
110 void MTimeBar::draw_time()
111 {
112
113         char string[BCTEXTLEN];
114         int sample_rate = mwindow->edl->session->sample_rate;
115         double frame_rate = mwindow->edl->session->frame_rate;
116 // Seconds between text markings
117         double text_interval = 3600.0;
118 // Seconds between tick marks
119         double tick_interval = 3600.0;
120
121
122 // Calculate tick mark spacing, number spacing, and starting point based
123 // on zoom, time format, project settings.
124
125 // If the time format is for audio, mark round numbers of samples based on
126 // samplerate.
127 // Fow low zoom, mark tens of samples.
128
129 // If the time format is for video, mark round number of frames based on
130 // framerate.
131 // For low zoom, mark individual frames.
132
133         //int64_t windowspan = mwindow->edl->local_session->zoom_sample * get_w();
134
135         draw_range();
136
137
138
139
140
141 // Number of seconds per pixel
142         double time_per_pixel = (double)mwindow->edl->local_session->zoom_sample /
143                 sample_rate;
144 // Seconds in each frame
145         double frame_seconds = (double)1.0 / frame_rate;
146 // Starting time of view in seconds.
147         double view_start = mwindow->edl->local_session->view_start[pane->number] *
148                 time_per_pixel;
149 // Ending time of view in seconds
150         double view_end = (double)(mwindow->edl->local_session->view_start[pane->number] +
151                 get_w()) * time_per_pixel;
152 // Get minimum distance between text marks
153         int min_pixels1 = get_text_width(MEDIUMFONT,
154                 Units::totext(string,
155                         view_start,
156                         mwindow->edl->session->time_format,
157                         sample_rate,
158                         mwindow->edl->session->frame_rate,
159                         mwindow->edl->session->frames_per_foot)) + TEXT_MARGIN;
160         int min_pixels2 = get_text_width(MEDIUMFONT,
161                 Units::totext(string,
162                         view_end,
163                         mwindow->edl->session->time_format,
164                         sample_rate,
165                         mwindow->edl->session->frame_rate,
166                         mwindow->edl->session->frames_per_foot)) + TEXT_MARGIN;
167         int min_pixels = (int)MAX(min_pixels1, min_pixels2);
168
169
170 // Minimum seconds between text marks
171         double min_time = (double)min_pixels *
172                 mwindow->edl->local_session->zoom_sample /
173                 sample_rate;
174
175
176 // Get first text mark on or before window start
177         int64_t starting_mark = 0;
178
179         int progression = 1;
180
181 // Default text spacing
182         text_interval = 0.5;
183         double prev_text_interval = 1.0;
184
185         while(text_interval >= min_time)
186         {
187                 prev_text_interval = text_interval;
188                 if(progression == 0)
189                 {
190                         text_interval /= 2;
191                         progression++;
192                 }
193                 else
194                 if(progression == 1)
195                 {
196                         text_interval /= 2;
197                         progression++;
198                 }
199                 else
200                 if(progression == 2)
201                 {
202                         text_interval /= 2.5;
203                         progression = 0;
204                 }
205         }
206
207         text_interval = prev_text_interval;
208
209         if(1 >= min_time)
210                 ;
211         else
212         if(2 >= min_time)
213                 text_interval = 2;
214         else
215         if(5 >= min_time)
216                 text_interval = 5;
217         else
218         if(10 >= min_time)
219                 text_interval = 10;
220         else
221         if(15 >= min_time)
222                 text_interval = 15;
223         else
224         if(20 >= min_time)
225                 text_interval = 20;
226         else
227         if(30 >= min_time)
228                 text_interval = 30;
229         else
230         if(60 >= min_time)
231                 text_interval = 60;
232         else
233         if(120 >= min_time)
234                 text_interval = 120;
235         else
236         if(300 >= min_time)
237                 text_interval = 300;
238         else
239         if(600 >= min_time)
240                 text_interval = 600;
241         else
242         if(1200 >= min_time)
243                 text_interval = 1200;
244         else
245         if(1800 >= min_time)
246                 text_interval = 1800;
247         else
248         if(3600 >= min_time)
249                 text_interval = 3600;
250
251 // Set text interval
252         switch(mwindow->edl->session->time_format)
253         {
254                 case TIME_FEET_FRAMES:
255                 {
256                         double foot_seconds = frame_seconds * mwindow->edl->session->frames_per_foot;
257                         if(frame_seconds >= min_time)
258                                 text_interval = frame_seconds;
259                         else
260                         if(foot_seconds / 8.0 > min_time)
261                                 text_interval = frame_seconds * mwindow->edl->session->frames_per_foot / 8.0;
262                         else
263                         if(foot_seconds / 4.0 > min_time)
264                                 text_interval = frame_seconds * mwindow->edl->session->frames_per_foot / 4.0;
265                         else
266                         if(foot_seconds / 2.0 > min_time)
267                                 text_interval = frame_seconds * mwindow->edl->session->frames_per_foot / 2.0;
268                         else
269                         if(foot_seconds > min_time)
270                                 text_interval = frame_seconds * mwindow->edl->session->frames_per_foot;
271                         else
272                         if(foot_seconds * 2 >= min_time)
273                                 text_interval = foot_seconds * 2;
274                         else
275                         if(foot_seconds * 5 >= min_time)
276                                 text_interval = foot_seconds * 5;
277                         else
278                         {
279
280                                 for(int factor = 10, progression = 0; factor <= 100000; )
281                                 {
282                                         if(foot_seconds * factor >= min_time)
283                                         {
284                                                 text_interval = foot_seconds * factor;
285                                                 break;
286                                         }
287
288                                         if(progression == 0)
289                                         {
290                                                 factor = (int)(factor * 2.5);
291                                                 progression++;
292                                         }
293                                         else
294                                         if(progression == 1)
295                                         {
296                                                 factor = (int)(factor * 2);
297                                                 progression++;
298                                         }
299                                         else
300                                         if(progression == 2)
301                                         {
302                                                 factor = (int)(factor * 2);
303                                                 progression = 0;
304                                         }
305                                 }
306
307                         }
308                         break;
309                 }
310
311                 case TIME_FRAMES:
312                 case TIME_HMSF:
313 // One frame per text mark
314                         if(frame_seconds >= min_time)
315                                 text_interval = frame_seconds;
316                         else
317                         if(frame_seconds * 2 >= min_time)
318                                 text_interval = frame_seconds * 2;
319                         else
320                         if(frame_seconds * 5 >= min_time)
321                                 text_interval = frame_seconds * 5;
322                         else
323                         {
324
325                                 for(int factor = 10, progression = 0; factor <= 100000; )
326                                 {
327                                         if(frame_seconds * factor >= min_time)
328                                         {
329                                                 text_interval = frame_seconds * factor;
330                                                 break;
331                                         }
332
333                                         if(progression == 0)
334                                         {
335                                                 factor = (int)(factor * 2.5);
336                                                 progression++;
337                                         }
338                                         else
339                                         if(progression == 1)
340                                         {
341                                                 factor = (int)(factor * 2);
342                                                 progression++;
343                                         }
344                                         else
345                                         if(progression == 2)
346                                         {
347                                                 factor = (int)(factor * 2);
348                                                 progression = 0;
349                                         }
350                                 }
351
352                         }
353                         break;
354
355                 default:
356                         break;
357         }
358
359 // Sanity
360         while(text_interval < min_time)
361         {
362                 text_interval *= 2;
363         }
364
365 // Set tick interval
366         tick_interval = text_interval;
367
368         switch(mwindow->edl->session->time_format)
369         {
370                 case TIME_HMSF:
371                 case TIME_FEET_FRAMES:
372                 case TIME_FRAMES:
373                         if(frame_seconds / time_per_pixel > TICK_SPACING)
374                                 tick_interval = frame_seconds;
375                         break;
376         }
377
378 // Get first text mark on or before window start
379         starting_mark = (int64_t)((double)mwindow->edl->local_session->view_start[pane->number] *
380                 time_per_pixel / text_interval);
381
382         double start_position = (double)starting_mark * text_interval;
383         int64_t iteration = 0;
384
385
386 //printf("text_interval=%f\n", text_interval);
387         while(start_position + text_interval * iteration < view_end)
388         {
389                 double position1 = start_position + text_interval * iteration;
390                 int pixel = (int64_t)(position1 / time_per_pixel) -
391                         mwindow->edl->local_session->view_start[pane->number];
392                 int pixel1 = pixel;
393
394                 Units::totext(string,
395                         position1,
396                         mwindow->edl->session->time_format,
397                         sample_rate,
398                         mwindow->edl->session->frame_rate,
399                         mwindow->edl->session->frames_per_foot);
400                 set_color(get_resources()->default_text_color);
401                 set_font(MEDIUMFONT);
402
403                 draw_text(pixel + TEXT_MARGIN, get_text_ascent(MEDIUMFONT), string);
404                 draw_line(pixel, LINE_MARGIN, pixel, get_h() - 2);
405
406                 double position2 = start_position + text_interval * (iteration + 1);
407                 int pixel2 = (int64_t)(position2 / time_per_pixel) -
408                         mwindow->edl->local_session->view_start[pane->number];
409
410                 for(double tick_position = position1;
411                         tick_position < position2;
412                         tick_position += tick_interval)
413                 {
414                         pixel = (int64_t)(tick_position / time_per_pixel) -
415                                 mwindow->edl->local_session->view_start[pane->number];
416                         if(labs(pixel - pixel1) > 1 &&
417                                 labs(pixel - pixel2) > 1)
418                                 draw_line(pixel, TICK_MARGIN, pixel, get_h() - 2);
419                 }
420                 iteration++;
421         }
422
423
424 }
425
426 void MTimeBar::draw_range()
427 {
428         int x1 = 0, x2 = 0;
429         if(mwindow->edl->tracks->total_playable_vtracks() &&
430                 mwindow->preferences->use_brender)
431         {
432                 double time_per_pixel = (double)mwindow->edl->local_session->zoom_sample /
433                         mwindow->edl->session->sample_rate;
434                 x1 = (int)(mwindow->edl->session->brender_start / time_per_pixel) -
435                         mwindow->edl->local_session->view_start[pane->number];
436                 x2 = (int)(mwindow->session->brender_end / time_per_pixel) -
437                         mwindow->edl->local_session->view_start[pane->number];
438         }
439
440         if(x2 > x1 &&
441                 x1 < get_w() &&
442                 x2 > 0)
443         {
444                 draw_top_background(get_parent(), 0, 0, x1, get_h());
445
446                 draw_3segmenth(x1, 0, x2 - x1, mwindow->theme->get_image("timebar_brender"));
447
448                 draw_top_background(get_parent(), x2, 0, get_w() - x2, get_h());
449         }
450         else
451         {
452                 draw_top_background(get_parent(), 0, 0, get_w(), get_h());
453         }
454
455
456 //      int64_t pixel = position_to_pixel(
457 //              mwindow->edl->local_session->get_selectionstart(1));
458 //
459 //      set_color(mwindow->theme->timebar_cursor_colorg);
460 //      draw_line(pixel, 0, pixel, get_h());
461 //printf("MTimeBar::draw_range %f %f\n", mwindow->session->brender_end, time_per_pixel);
462 }
463
464 void MTimeBar::select_label(double position)
465 {
466         EDL *edl = mwindow->edl;
467
468         gui->unlock_window();
469         gui->mbuttons->transport->handle_transport(STOP, 1, 0, 0);
470         gui->lock_window();
471
472         position = mwindow->edl->align_to_frame(position, 1);
473
474         if(shift_down())
475         {
476                 if(position > edl->local_session->get_selectionend(1) / 2 +
477                         edl->local_session->get_selectionstart(1) / 2)
478                 {
479
480                         edl->local_session->set_selectionend(position);
481                 }
482                 else
483                 {
484                         edl->local_session->set_selectionstart(position);
485                 }
486         }
487         else
488         {
489                 edl->local_session->set_selectionstart(position);
490                 edl->local_session->set_selectionend(position);
491         }
492
493 // Que the CWindow
494         mwindow->cwindow->update(1, 0, 0, 0, 1);
495
496         gui->hide_cursor(0);
497         gui->draw_cursor(1);
498         gui->flash_canvas(1);
499         gui->zoombar->update();
500         update_highlights();
501         activate_timeline();
502 }
503
504
505 int MTimeBar::resize_event()
506 {
507         reposition_window(mwindow->theme->mtimebar_x,
508                 mwindow->theme->mtimebar_y,
509                 mwindow->theme->mtimebar_w,
510                 mwindow->theme->mtimebar_h);
511         update(0);
512         return 1;
513 }
514
515 int MTimeBar::resize_event(int x, int y, int w, int h)
516 {
517         reposition_window(x,
518                 y,
519                 w,
520                 h);
521         update(0);
522         return 1;
523 }
524
525 // int MTimeBar::test_preview(int buttonpress)
526 // {
527 //      int result = 0;
528 //      return result;
529 // }
530 //
531
532
533 void MTimeBar::handle_mwindow_drag()
534 {
535 //printf("TimeBar::cursor_motion_event %d %d\n", __LINE__, current_operation);
536         int relative_cursor_x = pane->canvas->get_relative_cursor_x();
537         if(relative_cursor_x >= pane->canvas->get_w() ||
538                 relative_cursor_x < 0)
539         {
540                 pane->canvas->start_dragscroll();
541         }
542         else
543         if(relative_cursor_x < pane->canvas->get_w() &&
544                 relative_cursor_x >= 0)
545         {
546                 pane->canvas->stop_dragscroll();
547         }
548
549         update(0);
550 }
551
552 void MTimeBar::update(int flush)
553 {
554         TimeBar::update(flush);
555 }
556
557 void MTimeBar::update_clock(double position)
558 {
559         if(!mwindow->cwindow->playback_engine->is_playing_back)
560                 gui->mainclock->update(position);
561 }
562
563 void MTimeBar::update_cursor()
564 {
565         int rx = get_relative_cursor_x();
566         double position = pixel_to_position(rx);
567
568         position = mwindow->edl->align_to_frame(position, 0);
569         position = MAX(0, position);
570
571         mwindow->select_point(position);
572         update(1);
573 }
574
575 double MTimeBar::test_highlight()
576 {
577 // Don't crash during initialization
578         if(pane->canvas)
579         {
580                 if(mwindow->session->current_operation == NO_OPERATION)
581                 {
582                         if(pane->canvas->is_event_win() &&
583                                 pane->canvas->cursor_inside())
584                         {
585                                 int cursor_x = pane->canvas->get_cursor_x();
586                                 double position = (double)cursor_x *
587                                         (double)mwindow->edl->local_session->zoom_sample /
588                                         (double)mwindow->edl->session->sample_rate +
589                                         (double)mwindow->edl->local_session->view_start[pane->number] *
590                                         (double)mwindow->edl->local_session->zoom_sample /
591                                         (double)mwindow->edl->session->sample_rate;
592                                 pane->canvas->timebar_position = mwindow->edl->align_to_frame(position, 0);
593                         }
594
595 //printf("MTimeBar::test_highlight %d %d %f\n", __LINE__, pane->canvas->cursor_inside(), pane->canvas->timebar_position);
596                         return pane->canvas->timebar_position;
597                 }
598                 else
599                 if(mwindow->session->current_operation == SELECT_REGION ||
600                         mwindow->session->current_operation == DRAG_EDITHANDLE2)
601                 {
602 //printf("MTimeBar::test_highlight %d %f\n", __LINE__, mwindow->gui->canvas->timebar_position);
603                         return pane->canvas->timebar_position;
604                 }
605
606                 return -1;
607         }
608         else
609         {
610                 return -1;
611         }
612 }
613
614 int MTimeBar::repeat_event(int64_t duration)
615 {
616         if(!pane->canvas->drag_scroll) return 0;
617         if(duration != BC_WindowBase::get_resources()->scroll_repeat) return 0;
618
619         int distance = 0;
620         int x_movement = 0;
621         int relative_cursor_x = pane->canvas->get_relative_cursor_x();
622         if(current_operation == TIMEBAR_DRAG)
623         {
624                 if(relative_cursor_x >= pane->canvas->get_w())
625                 {
626                         distance = relative_cursor_x - pane->canvas->get_w();
627                         x_movement = 1;
628                 }
629                 else
630                 if(relative_cursor_x < 0)
631                 {
632                         distance = relative_cursor_x;
633                         x_movement = 1;
634                 }
635
636
637
638                 if(x_movement)
639                 {
640                         update_cursor();
641                         mwindow->samplemovement(
642                                 mwindow->edl->local_session->view_start[pane->number] + distance,
643                                 pane->number);
644                 }
645                 return 1;
646         }
647
648         return 0;
649 }
650
651 int MTimeBar::button_press_event()
652 {
653         int result = 0;
654
655         if(is_event_win() && cursor_above() && get_buttonpress() == 3)
656         {
657                 menu->update();
658                 menu->activate_menu();
659                 result = 1;
660         }
661
662         if(!result) return TimeBar::button_press_event();
663         return result;
664 }
665
666
667 void MTimeBar::activate_timeline()
668 {
669         pane->activate();
670 }
671
672
673
674
675
676
677 TimeBarPopupItem::TimeBarPopupItem(MWindow *mwindow,
678         TimeBarPopup *menu,
679         const char *text,
680         int value)
681  : BC_MenuItem(text)
682 {
683         this->mwindow = mwindow;
684         this->menu = menu;
685         this->value = value;
686 }
687
688 int TimeBarPopupItem::handle_event()
689 {
690         mwindow->edl->session->time_format = value;
691         mwindow->gui->update(0, 0, 1, 0, 0, 1, 0);
692         mwindow->gui->redraw_time_dependancies();
693         return 1;
694 }
695
696
697
698 TimeBarPopup::TimeBarPopup(MWindow *mwindow)
699  : BC_PopupMenu(0,
700                 0,
701                 0,
702                 "",
703                 0)
704 {
705         this->mwindow = mwindow;
706 }
707
708 TimeBarPopup::~TimeBarPopup()
709 {
710 }
711
712
713 void TimeBarPopup::create_objects()
714 {
715         add_item(items[0] = new TimeBarPopupItem(mwindow,
716                 this,
717                 TIME_HMS_TEXT,
718                 TIME_HMS));
719         add_item(items[1] = new TimeBarPopupItem(mwindow,
720                 this,
721                 TIME_HMSF_TEXT,
722                 TIME_HMSF));
723         add_item(items[2] = new TimeBarPopupItem(mwindow,
724                 this,
725                 TIME_FRAMES_TEXT,
726                 TIME_FRAMES));
727         add_item(items[3] = new TimeBarPopupItem(mwindow,
728                 this,
729                 TIME_SAMPLES_TEXT,
730                 TIME_SAMPLES));
731         add_item(items[4] = new TimeBarPopupItem(mwindow,
732                 this,
733                 TIME_SAMPLES_HEX_TEXT,
734                 TIME_SAMPLES_HEX));
735         add_item(items[5] = new TimeBarPopupItem(mwindow,
736                 this,
737                 TIME_SECONDS_TEXT,
738                 TIME_SECONDS));
739         add_item(items[6] = new TimeBarPopupItem(mwindow,
740                 this,
741                 TIME_FEET_FRAMES_TEXT,
742                 TIME_FEET_FRAMES));
743 }
744
745 void TimeBarPopup::update()
746 {
747         for(int i = 0; i < TOTAL_TIMEFORMATS; i++)
748         {
749                 if(items[i]->value == mwindow->edl->session->time_format)
750                 {
751                         items[i]->set_checked(1);
752                 }
753                 else
754                 {
755                         items[i]->set_checked(0);
756                 }
757         }
758 }
759
760
761
762
763