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