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