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