no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / mwindowmove.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
5  * Copyright (C) 2003-2016 Cinelerra CV contributors
6  *
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.
11  *
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.
16  *
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
20  *
21  */
22
23 #include "automation.h"
24 #include "autos.h"
25 #include "clip.h"
26 #include "cplayback.h"
27 #include "cwindow.h"
28 #include "cwindowgui.h"
29 #include "edits.h"
30 #include "edl.h"
31 #include "edlsession.h"
32 #include "gwindowgui.h"
33 #include "keyframe.h"
34 #include "labels.h"
35 #include "localsession.h"
36 #include "maincursor.h"
37 #include "mainmenu.h"
38 #include "mainsession.h"
39 #include "mtimebar.h"
40 #include "mwindow.h"
41 #include "mwindowgui.h"
42 #include "patchbay.h"
43 #include "playbackengine.h"
44 #include "plugin.h"
45 #include "pluginset.h"
46 #include "resourcethread.h"
47 #include "samplescroll.h"
48 #include "theme.h"
49 #include "trackcanvas.h"
50 #include "tracks.h"
51 #include "track.h"
52 #include "transportque.h"
53 #include "zoombar.h"
54
55
56 void MWindow::update_plugins()
57 {
58 // Show plugins which are visible and hide plugins which aren't
59 // Update plugin pointers in plugin servers
60 }
61
62
63 int MWindow::expand_sample()
64 {
65         if(gui)
66         {
67                 if(edl->local_session->zoom_sample < 0x100000)
68                 {
69                         edl->local_session->zoom_sample *= 2;
70                         gui->zoombar->sample_zoom->update(edl->local_session->zoom_sample);
71                         zoom_sample(edl->local_session->zoom_sample);
72                 }
73         }
74         return 0;
75 }
76
77 int MWindow::zoom_in_sample()
78 {
79         if(gui)
80         {
81                 if(edl->local_session->zoom_sample > 1)
82                 {
83                         edl->local_session->zoom_sample /= 2;
84                         gui->zoombar->sample_zoom->update(edl->local_session->zoom_sample);
85                         zoom_sample(edl->local_session->zoom_sample);
86                 }
87         }
88         return 0;
89 }
90
91 int MWindow::zoom_sample(int64_t zoom_sample)
92 {
93         CLAMP(zoom_sample, 1, 0x100000);
94         edl->local_session->zoom_sample = zoom_sample;
95         find_cursor();
96
97         TimelinePane *pane = gui->get_focused_pane();
98         samplemovement(edl->local_session->view_start[pane->number], pane->number);
99         return 0;
100 }
101
102 void MWindow::find_cursor()
103 {
104         TimelinePane *pane = gui->get_focused_pane();
105         edl->local_session->view_start[pane->number] =
106                 Units::round((edl->local_session->get_selectionend(1) +
107                 edl->local_session->get_selectionstart(1)) /
108                 2 *
109                 edl->session->sample_rate /
110                 edl->local_session->zoom_sample -
111                 (double)pane->canvas->get_w() /
112                 2);
113
114         if(edl->local_session->view_start[pane->number] < 0)
115                 edl->local_session->view_start[pane->number] = 0;
116 }
117
118
119 void MWindow::fit_selection()
120 {
121         if(EQUIV(edl->local_session->get_selectionstart(1),
122                 edl->local_session->get_selectionend(1)))
123         {
124                 double total_samples = edl->tracks->total_length() *
125                         edl->session->sample_rate;
126                 TimelinePane *pane = gui->get_focused_pane();
127                 for(edl->local_session->zoom_sample = 1;
128                         pane->canvas->get_w() * edl->local_session->zoom_sample < total_samples;
129                         edl->local_session->zoom_sample *= 2)
130                         ;
131         }
132         else
133         {
134                 double total_samples = (edl->local_session->get_selectionend(1) -
135                         edl->local_session->get_selectionstart(1)) *
136                         edl->session->sample_rate;
137                 TimelinePane *pane = gui->get_focused_pane();
138                 for(edl->local_session->zoom_sample = 1;
139                         pane->canvas->get_w() * edl->local_session->zoom_sample < total_samples;
140                         edl->local_session->zoom_sample *= 2)
141                         ;
142         }
143
144         edl->local_session->zoom_sample = MIN(0x100000,
145                 edl->local_session->zoom_sample);
146         zoom_sample(edl->local_session->zoom_sample);
147 }
148
149
150 void MWindow::fit_autos(int all)
151 {
152         float min = 0, max = 0;
153         double start, end;
154
155 // Test all autos
156         if(EQUIV(edl->local_session->get_selectionstart(1),
157                 edl->local_session->get_selectionend(1)))
158         {
159                 start = 0;
160                 end = edl->tracks->total_length();
161         }
162         else
163 // Test autos in highlighting only
164         {
165                 start = edl->local_session->get_selectionstart(1);
166                 end = edl->local_session->get_selectionend(1);
167         }
168
169         int forstart = edl->local_session->zoombar_showautotype;
170         int forend   = edl->local_session->zoombar_showautotype + 1;
171
172         if( all ) {
173                 forstart = 0;
174                 forend   = AUTOGROUPTYPE_COUNT;
175         }
176
177         for (int i = forstart; i < forend; i++)
178         {
179 // Adjust min and max
180                 edl->tracks->get_automation_extents(&min, &max, start, end, i);
181 //printf("MWindow::fit_autos %d %f %f results in ", i, min, max);
182
183                 float range = max - min;
184                 switch (i)
185                 {
186                 case AUTOGROUPTYPE_AUDIO_FADE:
187                         if (range < 1) {
188                                 min = MIN(min, edl->local_session->automation_mins[i]);
189                                 max = MAX(max, edl->local_session->automation_maxs[i]);
190                                 if( min >= max-0.1 ) { min = -80.0; min = 6.0; }
191                         }
192                         break;
193                 case AUTOGROUPTYPE_VIDEO_FADE:
194                         if (range < 1) {
195                                 min = MIN(min, edl->local_session->automation_mins[i]);
196                                 max = MAX(max, edl->local_session->automation_maxs[i]);
197                                 if( min >= max-0.1 ) { min = 0.0; min = 100.0; }
198                         }
199                         break;
200                 case AUTOGROUPTYPE_ZOOM:
201                         if (range < 0.001) {
202                                 min = floor(min*50)/100;
203                                 max = floor(max*200)/100;
204                         }
205                         break;
206                 case AUTOGROUPTYPE_SPEED:
207                         if (range < 0.001) {
208                                 min = floor(min*5)/100;
209                                 max = floor(max*300)/100;
210                         }
211                         break;
212                 case AUTOGROUPTYPE_X:
213                 case AUTOGROUPTYPE_Y:
214                         if (range < 1) {
215                                 float scale = bmin(edl->session->output_w, edl->session->output_h);
216                                 min = floor((min+max)/2) - 0.5*scale;
217                                 max = floor((min+max)/2) + 0.5*scale;
218                         }
219                         break;
220                 }
221 //printf("%f %f\n", min, max);
222                 if (!Automation::autogrouptypes_fixedrange[i])
223                 {
224                         edl->local_session->automation_mins[i] = min;
225                         edl->local_session->automation_maxs[i] = max;
226                 }
227         }
228
229 // Show range in zoombar
230         gui->zoombar->update();
231
232 // Draw
233         gui->draw_overlays(1);
234 }
235
236
237 void MWindow::change_currentautorange(int autogrouptype, int increment, int changemax)
238 {
239         float val;
240         if (changemax) {
241                 val = edl->local_session->automation_maxs[autogrouptype];
242         } else {
243                 val = edl->local_session->automation_mins[autogrouptype];
244         }
245
246         if (increment)
247         {
248                 switch (autogrouptype) {
249                 case AUTOGROUPTYPE_AUDIO_FADE:
250                         val += 2;
251                         break;
252                 case AUTOGROUPTYPE_VIDEO_FADE:
253                         val += 1;
254                         break;
255                 case AUTOGROUPTYPE_ZOOM:
256                 case AUTOGROUPTYPE_SPEED:
257                         if (val == 0)
258                                 val = 0.001;
259                         else
260                                 val = val*2;
261                         break;
262                 case AUTOGROUPTYPE_X:
263                 case AUTOGROUPTYPE_Y:
264                         val = floor(val + 50);
265                         break;
266                 }
267         }
268         else
269         { // decrement
270                 switch (autogrouptype) {
271                 case AUTOGROUPTYPE_AUDIO_FADE:
272                         val -= 2;
273                         break;
274                 case AUTOGROUPTYPE_VIDEO_FADE:
275                         val -= 1;
276                         break;
277                 case AUTOGROUPTYPE_ZOOM:
278                 case AUTOGROUPTYPE_SPEED:
279                         if (val > 0) val = val/2;
280                         break;
281                 case AUTOGROUPTYPE_X:
282                 case AUTOGROUPTYPE_Y:
283                         val = floor(val-50);
284                         break;
285                 }
286         }
287
288         AUTOMATIONVIEWCLAMPS(val, autogrouptype);
289
290         if (changemax) {
291                 if (val > edl->local_session->automation_mins[autogrouptype])
292                         edl->local_session->automation_maxs[autogrouptype] = val;
293         }
294         else
295         {
296                 if (val < edl->local_session->automation_maxs[autogrouptype])
297                         edl->local_session->automation_mins[autogrouptype] = val;
298         }
299 }
300
301 void MWindow::update_autorange(int type, int increment, int use_max)
302 {
303         gui->lock_window("MWindow::update_autorange");
304         int group = Automation::autogrouptype(type, 0);
305         change_currentautorange(group, increment, use_max);
306         int color = GWindowGUI::auto_colors[type];
307         gui->zoombar->update_autozoom(group, color);
308         gui->draw_overlays(0);
309         gui->update_patchbay();
310         gui->flash_canvas(1);
311         gui->unlock_window();
312 }
313
314 void MWindow::expand_autos(int changeall, int domin, int domax)
315 {
316         if (changeall)
317                 for (int i = 0; i < AUTOGROUPTYPE_COUNT; i++) {
318                         if (domin) change_currentautorange(i, 1, 0);
319                         if (domax) change_currentautorange(i, 1, 1);
320                 }
321         else
322         {
323                 if (domin) change_currentautorange(edl->local_session->zoombar_showautotype, 1, 0);
324                 if (domax) change_currentautorange(edl->local_session->zoombar_showautotype, 1, 1);
325         }
326         gui->zoombar->update_autozoom();
327         gui->draw_overlays(0);
328         gui->update_patchbay();
329         gui->flash_canvas(1);
330 }
331
332 void MWindow::shrink_autos(int changeall, int domin, int domax)
333 {
334         if (changeall)
335                 for (int i = 0; i < AUTOGROUPTYPE_COUNT; i++) {
336                         if (domin) change_currentautorange(i, 0, 0);
337                         if (domax) change_currentautorange(i, 0, 1);
338                 }
339         else
340         {
341                 if (domin) change_currentautorange(edl->local_session->zoombar_showautotype, 0, 0);
342                 if (domax) change_currentautorange(edl->local_session->zoombar_showautotype, 0, 1);
343         }
344         gui->zoombar->update_autozoom();
345         gui->draw_overlays(0);
346         gui->update_patchbay();
347         gui->flash_canvas(1);
348 }
349
350
351 void MWindow::zoom_autos(float min, float max)
352 {
353         int i = edl->local_session->zoombar_showautotype;
354         edl->local_session->automation_mins[i] = min;
355         edl->local_session->automation_maxs[i] = max;
356         gui->zoombar->update_autozoom();
357         gui->draw_overlays(1);
358 }
359
360
361 void MWindow::zoom_amp(int64_t zoom_amp)
362 {
363         edl->local_session->zoom_y = zoom_amp;
364         gui->draw_canvas(0, 0);
365         gui->flash_canvas(0);
366         gui->update_patchbay();
367         gui->flush();
368 }
369
370 void MWindow::zoom_atrack(int64_t zoom)
371 {
372         int64_t old_zoom = edl->local_session->zoom_atrack;
373         CLAMP(zoom, MIN_TRACK_ZOOM, MAX_TRACK_ZOOM);
374         edl->local_session->zoom_atrack = zoom;
375
376         edl->local_session->zoom_atrack = zoom;
377         for( Track *track= edl->tracks->first; track; track=track->next ) {
378                 if( track->data_type != TRACK_AUDIO ) continue;
379                 track->data_h = zoom;
380         }
381 // shift row position
382         for( int i=0; i<TOTAL_PANES; ++i ) edl->local_session->track_start[i] =
383                 (edl->local_session->track_start[i] * zoom) / old_zoom;
384         edl->tracks->update_y_pixels(theme);
385         gui->draw_trackmovement();
386 }
387
388 void MWindow::zoom_vtrack(int64_t zoom)
389 {
390         int64_t old_zoom = edl->local_session->zoom_vtrack;
391         CLAMP(zoom, MIN_TRACK_ZOOM, MAX_TRACK_ZOOM);
392         edl->local_session->zoom_vtrack = zoom;
393
394         for( Track *track= edl->tracks->first; track; track=track->next ) {
395                 if( track->data_type != TRACK_VIDEO ) continue;
396                 track->data_h = zoom;
397         }
398 // shift row position
399         for( int i=0; i<TOTAL_PANES; ++i ) edl->local_session->track_start[i] =
400                 (edl->local_session->track_start[i] * zoom) / old_zoom;
401         edl->tracks->update_y_pixels(theme);
402         gui->draw_trackmovement();
403 }
404
405 void MWindow::trackmovement(int offset, int pane_number)
406 {
407         edl->local_session->track_start[pane_number] += offset;
408         if(edl->local_session->track_start[pane_number] < 0)
409                 edl->local_session->track_start[pane_number] = 0;
410
411         if(pane_number == TOP_RIGHT_PANE ||
412                 pane_number == TOP_LEFT_PANE)
413         {
414                 edl->local_session->track_start[TOP_LEFT_PANE] =
415                         edl->local_session->track_start[TOP_RIGHT_PANE] =
416                         edl->local_session->track_start[pane_number];
417         }
418         else
419         if(pane_number == BOTTOM_RIGHT_PANE ||
420                 pane_number == BOTTOM_LEFT_PANE)
421         {
422                 edl->local_session->track_start[BOTTOM_LEFT_PANE] =
423                         edl->local_session->track_start[BOTTOM_RIGHT_PANE] =
424                         edl->local_session->track_start[pane_number];
425         }
426
427
428         edl->tracks->update_y_pixels(theme);
429         gui->draw_trackmovement();
430 }
431
432 void MWindow::move_up(int64_t distance)
433 {
434         TimelinePane *pane = gui->get_focused_pane();
435         if(distance == 0) distance = pane->canvas->get_h() / 10;
436         trackmovement(-distance, pane->number);
437 }
438
439 void MWindow::move_down(int64_t distance)
440 {
441         TimelinePane *pane = gui->get_focused_pane();
442         if(distance == 0) distance = pane->canvas->get_h() / 10;
443         trackmovement(distance, pane->number);
444 }
445
446 int MWindow::goto_end()
447 {
448         TimelinePane *pane = gui->get_focused_pane();
449         int64_t old_view_start = edl->local_session->view_start[pane->number];
450
451         if( edl->tracks->total_length() > (double)pane->canvas->get_w() *
452                 edl->local_session->zoom_sample / edl->session->sample_rate ) {
453                 edl->local_session->view_start[pane->number] =
454                         Units::round(edl->tracks->total_length() *
455                                 edl->session->sample_rate /
456                                 edl->local_session->zoom_sample -
457                                 pane->canvas->get_w() /
458                                 2);
459         }
460         else
461         {
462                 edl->local_session->view_start[pane->number] = 0;
463         }
464
465         if(gui->shift_down())
466         {
467                 edl->local_session->set_selectionend(edl->tracks->total_length());
468         }
469         else
470         {
471                 edl->local_session->set_selectionstart(edl->tracks->total_length());
472                 edl->local_session->set_selectionend(edl->tracks->total_length());
473         }
474
475         if(edl->local_session->view_start[pane->number] != old_view_start)
476         {
477                 samplemovement(edl->local_session->view_start[pane->number], pane->number);
478                 gui->draw_samplemovement();
479         }
480
481         update_plugin_guis();
482
483         gui->update_patchbay();
484         gui->update_cursor();
485         gui->activate_timeline();
486         gui->zoombar->update();
487         gui->update_timebar(1);
488         cwindow->update(1, 0, 0, 0, 1);
489         return 0;
490 }
491
492 int MWindow::goto_start()
493 {
494         TimelinePane *pane = gui->get_focused_pane();
495         int64_t old_view_start = edl->local_session->view_start[pane->number];
496
497         edl->local_session->view_start[pane->number] = 0;
498         if(gui->shift_down())
499         {
500                 edl->local_session->set_selectionstart(0);
501         }
502         else
503         {
504                 edl->local_session->set_selectionstart(0);
505                 edl->local_session->set_selectionend(0);
506         }
507
508         if(edl->local_session->view_start[pane->number] != old_view_start)
509         {
510                 samplemovement(edl->local_session->view_start[pane->number], pane->number);
511                 gui->draw_samplemovement();
512         }
513
514         update_plugin_guis();
515         gui->update_patchbay();
516         gui->update_cursor();
517         gui->activate_timeline();
518         gui->zoombar->update();
519         gui->update_timebar(1);
520         cwindow->update(1, 0, 0, 0, 1);
521         return 0;
522 }
523
524 int MWindow::goto_position(double position)
525 {
526         position = edl->align_to_frame(position, 0);
527         if( position < 0 ) position = 0;
528         select_point(position);
529         gui->activate_timeline();
530         return 0;
531 }
532
533 int MWindow::samplemovement(int64_t view_start, int pane_number)
534 {
535         if( view_start < 0 ) view_start = 0;
536         edl->local_session->view_start[pane_number] = view_start;
537         if(edl->local_session->view_start[pane_number] < 0)
538                 edl->local_session->view_start[pane_number] = 0;
539
540         if(pane_number == TOP_LEFT_PANE ||
541                 pane_number == BOTTOM_LEFT_PANE)
542         {
543                 edl->local_session->view_start[TOP_LEFT_PANE] =
544                         edl->local_session->view_start[BOTTOM_LEFT_PANE] =
545                         edl->local_session->view_start[pane_number];
546         }
547         else
548         {
549                 edl->local_session->view_start[TOP_RIGHT_PANE] =
550                         edl->local_session->view_start[BOTTOM_RIGHT_PANE] =
551                         edl->local_session->view_start[pane_number];
552         }
553
554         gui->draw_samplemovement();
555
556         return 0;
557 }
558
559 int MWindow::move_left(int64_t distance)
560 {
561         TimelinePane *pane = gui->get_focused_pane();
562         if(!distance)
563                 distance = pane->canvas->get_w() / 10;
564         edl->local_session->view_start[pane->number] -= distance;
565         samplemovement(edl->local_session->view_start[pane->number],
566                 pane->number);
567         return 0;
568 }
569
570 int MWindow::move_right(int64_t distance)
571 {
572         TimelinePane *pane = gui->get_focused_pane();
573         if(!distance)
574                 distance = pane->canvas->get_w() / 10;
575         edl->local_session->view_start[pane->number] += distance;
576         samplemovement(edl->local_session->view_start[pane->number],
577                 pane->number);
578         return 0;
579 }
580
581 void MWindow::select_all()
582 {
583         if( edl->local_session->get_selectionstart(1) == 0 &&
584             edl->local_session->get_selectionend(1) == edl->tracks->total_length() )
585                 edl->local_session->set_selectionend(0);
586         else {
587                 edl->local_session->set_selectionstart(0);
588                 edl->local_session->set_selectionend(edl->tracks->total_length());
589         }
590         gui->update(0, NORMAL_DRAW, 1, 1, 0, 1, 0);
591         gui->activate_timeline();
592         cwindow->update(1, 0, 0, 0, 1);
593         update_plugin_guis();
594 }
595
596 int MWindow::next_label(int shift_down)
597 {
598         double position = edl->local_session->get_selectionend(1);
599         double total_length = edl->tracks->total_length();
600         Label *current = edl->labels->next_label(position);
601         double new_position = current ? current->position : total_length;
602 // last playback endpoints as fake label positions
603         double playback_start = edl->local_session->playback_start;
604         double playback_end = edl->local_session->playback_end;
605         if( playback_start > position && playback_start < new_position )
606                 new_position = playback_start;
607         else if( playback_end > position && playback_end < new_position )
608                 new_position = playback_end;
609         if( new_position > total_length )
610                 new_position = total_length;
611         edl->local_session->set_selectionend(new_position);
612 //printf("MWindow::next_edit_handle %d\n", shift_down);
613         if( !shift_down )
614                 edl->local_session->set_selectionstart(new_position);
615         return find_selection(new_position);
616 }
617
618 int MWindow::prev_label(int shift_down)
619 {
620         double position = edl->local_session->get_selectionstart(1);
621         Label *current = edl->labels->prev_label(position);
622         double new_position = current ? current->position : 0;
623 // last playback endpoints as fake label positions
624         double playback_start = edl->local_session->playback_start;
625         double playback_end = edl->local_session->playback_end;
626         if( playback_end < position && playback_end > new_position )
627                 new_position = playback_end;
628         else if( playback_start < position && playback_start > new_position )
629                 new_position = playback_start;
630         if( new_position < 0 )
631                 new_position = 0;
632         edl->local_session->set_selectionstart(new_position);
633 //printf("MWindow::next_edit_handle %d\n", shift_down);
634         if( !shift_down )
635                 edl->local_session->set_selectionend(new_position);
636         return find_selection(new_position);
637 }
638
639 int MWindow::next_edit_handle(int shift_down)
640 {
641         double position = edl->local_session->get_selectionend(1);
642         double new_position = edl->next_edit(position);
643         double total_length = edl->tracks->total_length();
644         if( new_position >= total_length )
645                 new_position = total_length;
646         edl->local_session->set_selectionend(new_position);
647 //printf("MWindow::next_edit_handle %d\n", shift_down);
648         if( !shift_down )
649                 edl->local_session->set_selectionstart(new_position);
650         return find_selection(new_position);
651 }
652
653 int MWindow::prev_edit_handle(int shift_down)
654 {
655         double position = edl->local_session->get_selectionstart(1);
656         double new_position = edl->prev_edit(position);
657         if( new_position < 0 )
658                 new_position = 0;
659         edl->local_session->set_selectionstart(new_position);
660         if( !shift_down )
661                 edl->local_session->set_selectionend(new_position);
662         return find_selection(new_position);
663 }
664
665 int MWindow::nearest_plugin_keyframe(int shift_down, int dir)
666 {
667         KeyFrame *keyframe = 0;
668         double start = edl->local_session->get_selectionstart(1);
669         double end = edl->local_session->get_selectionend(1);
670         double position = dir == PLAY_FORWARD ? end : start;
671         double new_position = dir == PLAY_FORWARD ? start : end;
672         for( Track *track=edl->tracks->first; track; track=track->next ) {
673                 if( !track->is_armed() ) continue;
674                 for( int i=0; i<track->plugin_set.size(); ++i ) {
675                         PluginSet *plugin_set = track->plugin_set[i];
676                         int64_t pos = track->to_units(position, 0);
677                         KeyFrame *key = plugin_set->nearest_keyframe(pos, dir);
678                         if( !key ) continue;
679                         double key_position = track->from_units(key->position);
680                         if( keyframe && (dir == PLAY_FORWARD ?
681                                 key_position >= new_position :
682                                 new_position >= key_position ) ) continue;
683                         keyframe = key;  new_position = key_position;
684                 }
685         }
686
687         new_position = keyframe ?
688                 keyframe->autos->track->from_units(keyframe->position) :
689                 dir == PLAY_FORWARD ? edl->tracks->total_length() : 0;
690
691         if( !shift_down )
692                 start = end = new_position;
693         else if( dir == PLAY_FORWARD )
694                 end = new_position;
695         else
696                 start = new_position;
697
698         edl->local_session->set_selectionstart(start);
699         edl->local_session->set_selectionend(end);
700         return find_selection(new_position);
701 }
702
703 int MWindow::nearest_auto_keyframe(int shift_down, int dir)
704 {
705         Auto *keyframe = 0;
706         double start = edl->local_session->get_selectionstart(1);
707         double end = edl->local_session->get_selectionend(1);
708         double position = dir == PLAY_FORWARD ? end : start;
709         double new_position = dir == PLAY_FORWARD ? start : end;
710         for( Track *track=edl->tracks->first; track; track=track->next ) {
711                 if( !track->is_armed() ) continue;
712                 int64_t pos = track->to_units(position, 0);
713                 for( int i=0; i<AUTOMATION_TOTAL; ++i ) {
714                         Autos *autos = track->automation->autos[i];
715                         if( !autos ) continue;
716                         Auto *key = dir == PLAY_FORWARD ?
717                                  autos->nearest_after(pos) :
718                                  autos->nearest_before(pos);
719                         if( !key ) continue;
720                         double key_position = track->from_units(key->position);
721                         if( keyframe && (dir == PLAY_FORWARD ?
722                                 key_position >= new_position :
723                                 new_position >= key_position ) ) continue;
724                         keyframe = key;  new_position = key_position;
725                 }
726         }
727
728         new_position = keyframe ?
729                 keyframe->autos->track->from_units(keyframe->position) :
730                 dir == PLAY_FORWARD ? edl->tracks->total_length() : 0;
731
732         if( !shift_down )
733                 start = end = new_position;
734         else if( dir == PLAY_FORWARD )
735                 end = new_position;
736         else
737                 start = new_position;
738
739         edl->local_session->set_selectionstart(start);
740         edl->local_session->set_selectionend(end);
741         return find_selection(new_position);
742 }
743
744 int MWindow::find_selection(double position, int scroll_display)
745 {
746         update_plugin_guis();
747         TimelinePane *pane = gui->get_focused_pane();
748         double pixel_zoom = (double)edl->session->sample_rate / edl->local_session->zoom_sample;
749         if( !scroll_display ) {
750                 double timeline_start = edl->local_session->view_start[pane->number] / pixel_zoom;
751                 double timeline_end = timeline_start + pane->canvas->time_visible();
752                 if( position >= timeline_end || position < timeline_start )
753                         scroll_display = 1;
754         }
755         if( scroll_display ) {
756                 samplemovement((int64_t)(position * pixel_zoom - pane->canvas->get_w() / 2), pane->number);
757                 cwindow->update(1, 0, 0, 0, 0);
758         }
759         else {
760                 gui->update_patchbay();
761                 gui->update_timebar(0);
762                 gui->hide_cursor(0);
763                 gui->draw_cursor(0);
764                 gui->zoombar->update();
765                 gui->flash_canvas(1);
766                 cwindow->update(1, 0, 0, 0, 1);
767         }
768         return 0;
769 }
770
771 double MWindow::get_position()
772 {
773         return edl->local_session->get_selectionstart(1);
774 }
775
776 void MWindow::set_position(double position)
777 {
778         if( position != get_position() ) {
779                 if( position < 0 ) position = 0;
780                 edl->local_session->set_selectionstart(position);
781                 edl->local_session->set_selectionend(position);
782                 gui->lock_window();
783                 find_cursor();
784                 gui->update(1, NORMAL_DRAW, 1, 1, 1, 1, 0);
785                 gui->unlock_window();
786                 cwindow->update(1, 0, 0, 0, 0);
787         }
788 }
789
790
791 double MWindow::get_timecode_offset()
792 {
793         return edl->session->timecode_offset;
794 }
795
796 void MWindow::set_timecode_offset(double offset)
797 {
798         edl->session->time_format = TIME_TIMECODE;
799         edl->session->timecode_offset = offset;
800         gui->lock_window();
801         gui->update(1, NORMAL_DRAW, 1, 1, 1, 1, 0);
802         gui->unlock_window();
803         cwindow->update(1, 0, 0, 0, 0);
804 }
805
806
807 int MWindow::expand_y()
808 {
809         int result = edl->local_session->zoom_y * 2;
810         result = MIN(result, MAX_AMP_ZOOM);
811         zoom_amp(result);
812         gui->zoombar->update();
813         return 0;
814 }
815
816 int MWindow::zoom_in_y()
817 {
818         int result = edl->local_session->zoom_y / 2;
819         result = MAX(result, MIN_AMP_ZOOM);
820         zoom_amp(result);
821         gui->zoombar->update();
822         return 0;
823 }
824
825 int MWindow::expand_t()
826 {
827         int zoom = edl->local_session->zoom_atrack * 2;
828         zoom = MIN(zoom, MAX_TRACK_ZOOM);
829         zoom_atrack(zoom);
830         zoom = edl->local_session->zoom_vtrack * 2;
831         zoom = MIN(zoom, MAX_TRACK_ZOOM);
832         zoom_vtrack(zoom);
833         gui->zoombar->update();
834         return 0;
835 }
836
837 int MWindow::zoom_in_t()
838 {
839         int zoom = edl->local_session->zoom_atrack / 2;
840         zoom = MAX(zoom, MIN_TRACK_ZOOM);
841         zoom_atrack(zoom);
842         zoom = edl->local_session->zoom_vtrack / 2;
843         zoom = MAX(zoom, MIN_TRACK_ZOOM);
844         zoom_vtrack(zoom);
845         gui->zoombar->update();
846         return 0;
847 }
848
849 void MWindow::split_x()
850 {
851         gui->resource_thread->stop_draw(1);
852
853         if(gui->pane[TOP_RIGHT_PANE])
854         {
855                 gui->delete_x_pane(theme->mcanvas_w);
856                 edl->local_session->x_pane = -1;
857         }
858         else
859         {
860                 gui->create_x_pane(theme->mcanvas_w / 2);
861                 edl->local_session->x_pane = theme->mcanvas_w / 2;
862         }
863
864         gui->mainmenu->update_toggles(0);
865         gui->update_pane_dividers();
866         gui->update_cursor();
867         gui->draw_samplemovement();
868 // required to get new widgets to appear
869         gui->show_window();
870
871         gui->resource_thread->start_draw();
872 }
873
874 void MWindow::split_y()
875 {
876         gui->resource_thread->stop_draw(1);
877         if(gui->pane[BOTTOM_LEFT_PANE])
878         {
879                 gui->delete_y_pane(theme->mcanvas_h);
880                 edl->local_session->y_pane = -1;
881         }
882         else
883         {
884                 gui->create_y_pane(theme->mcanvas_h / 2);
885                 edl->local_session->y_pane = theme->mcanvas_h / 2;
886         }
887
888         gui->mainmenu->update_toggles(0);
889         gui->update_pane_dividers();
890         gui->update_cursor();
891         gui->draw_trackmovement();
892 // required to get new widgets to appear
893         gui->show_window();
894         gui->resource_thread->start_draw();
895 }
896