lots of small fixes for various irritations, return of snapshots, region list hiding...
[ardour.git] / gtk2_ardour / editor_canvas_events.cc
1 /*
2     Copyright (C) 2000 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include <cstdlib>
22 #include <cmath>
23
24 #include <ardour/diskstream.h>
25 #include <ardour/audioplaylist.h>
26
27 #include "editor.h"
28 #include "public_editor.h"
29 #include "regionview.h"
30 #include "streamview.h"
31 #include "crossfade_view.h"
32 #include "audio_time_axis.h"
33 #include "region_gain_line.h"
34 #include "automation_gain_line.h"
35 #include "automation_pan_line.h"
36 #include "automation_time_axis.h"
37 #include "redirect_automation_line.h"
38 #include "canvas_impl.h"
39 #include "simplerect.h"
40
41 #include "i18n.h"
42
43 using namespace sigc;
44 using namespace ARDOUR;
45 using namespace Gtk;
46
47 bool
48 Editor::track_canvas_scroll (GdkEventScroll* ev)
49 {
50         switch (ev->direction) {
51         case GDK_SCROLL_UP:
52                 scroll_tracks_up_line ();
53                 return true;
54                 break;
55
56         case GDK_SCROLL_DOWN:
57                 scroll_tracks_down_line ();
58                 return true;
59                 
60         default:
61                 /* no left/right handling yet */
62                 break;
63         }
64
65         return false;
66 }
67
68 bool
69 Editor::track_canvas_event (GdkEvent *event, ArdourCanvas::Item* item)
70 {
71         gint x, y;
72
73         /* this is the handler for events that are not handled by
74            items.
75         */
76
77         switch (event->type) {
78         case GDK_MOTION_NOTIFY:
79                 /* keep those motion events coming */
80                 track_canvas.get_pointer (x, y);
81                 return track_canvas_motion (event);
82
83         case GDK_BUTTON_PRESS:
84                 track_canvas.grab_focus();
85                 break;
86
87         case GDK_BUTTON_RELEASE:
88                 switch (event->button.button) {
89                 case 4:
90                 case 5:
91                         button_release_handler (item, event, NoItem);
92                         break;
93                 }
94                 break;
95
96         case GDK_SCROLL:
97                 track_canvas.grab_focus();
98                 track_canvas_scroll (&event->scroll);
99                 break;
100
101         default:
102                 break;
103         }
104
105         return FALSE;
106 }
107
108 bool
109 Editor::track_canvas_motion (GdkEvent *ev)
110 {
111         if (verbose_cursor_visible) {
112                 verbose_canvas_cursor->property_x() = ev->motion.x + 20;
113                 verbose_canvas_cursor->property_y() = ev->motion.y + 20;
114         }
115         return false;
116 }
117
118 bool
119 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
120 {
121         gint ret = FALSE;
122         
123         switch (event->type) {
124         case GDK_BUTTON_PRESS:
125         case GDK_2BUTTON_PRESS:
126         case GDK_3BUTTON_PRESS:
127                 ret = button_press_handler (item, event, type);
128                 break;
129         case GDK_BUTTON_RELEASE:
130                 ret = button_release_handler (item, event, type);
131                 break;
132         case GDK_MOTION_NOTIFY:
133                 ret = motion_handler (item, event, type);
134                 break;
135
136         case GDK_ENTER_NOTIFY:
137                 ret = enter_handler (item, event, type);
138                 break;
139
140         case GDK_LEAVE_NOTIFY:
141                 ret = leave_handler (item, event, type);
142                 break;
143
144         default:
145                 break;
146         }
147                         
148         return ret;
149 }
150
151 bool
152 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
153 {
154         gint ret = FALSE;
155
156         switch (event->type) {
157         case GDK_BUTTON_PRESS:
158         case GDK_2BUTTON_PRESS:
159         case GDK_3BUTTON_PRESS:
160                 clicked_regionview = rv;
161                 clicked_control_point = 0;
162                 clicked_trackview = &rv->get_time_axis_view();
163                 clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
164                 ret = button_press_handler (item, event, RegionItem);
165                 break;
166
167         case GDK_BUTTON_RELEASE:
168                 ret = button_release_handler (item, event, RegionItem);
169                 break;
170
171         case GDK_MOTION_NOTIFY:
172                 ret = motion_handler (item, event, RegionItem);
173                 break;
174
175         case GDK_ENTER_NOTIFY:
176                 set_entered_regionview (rv);
177                 break;
178
179         case GDK_LEAVE_NOTIFY:
180                 set_entered_regionview (0);
181                 break;
182
183         default:
184                 break;
185         }
186
187         return ret;
188 }
189
190 bool
191 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, AudioTimeAxisView *tv)
192 {
193         bool ret = FALSE;
194         
195         switch (event->type) {
196         case GDK_BUTTON_PRESS:
197         case GDK_2BUTTON_PRESS:
198         case GDK_3BUTTON_PRESS:
199                 clicked_regionview = 0;
200                 clicked_control_point = 0;
201                 clicked_trackview = tv;
202                 clicked_audio_trackview = tv;
203                 ret = button_press_handler (item, event, StreamItem);
204                 break;
205
206         case GDK_BUTTON_RELEASE:
207                 ret = button_release_handler (item, event, StreamItem);
208                 break;
209
210         case GDK_MOTION_NOTIFY:
211                 ret = motion_handler (item, event, StreamItem);
212                 break;
213
214         case GDK_ENTER_NOTIFY:
215                 break;
216
217         default:
218                 break;
219         }
220
221         return ret;
222 }
223
224
225
226 bool
227 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
228 {
229         bool ret = false;
230         
231         switch (event->type) {
232         case GDK_BUTTON_PRESS:
233         case GDK_2BUTTON_PRESS:
234         case GDK_3BUTTON_PRESS:
235                 clicked_regionview = 0;
236                 clicked_control_point = 0;
237                 clicked_trackview = atv;
238                 clicked_audio_trackview = 0;
239                 ret = button_press_handler (item, event, AutomationTrackItem);
240                 break;
241
242         case GDK_BUTTON_RELEASE:
243                 ret = button_release_handler (item, event, AutomationTrackItem);
244                 break;
245
246         case GDK_MOTION_NOTIFY:
247                 ret = motion_handler (item, event, AutomationTrackItem);
248                 break;
249
250         case GDK_ENTER_NOTIFY:
251                 ret = enter_handler (item, event, AutomationTrackItem);
252                 break;
253
254         case GDK_LEAVE_NOTIFY:
255                 ret = leave_handler (item, event, AutomationTrackItem);
256                 break;
257
258         default:
259                 break;
260         }
261
262         return ret;
263 }
264
265 bool
266 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
267 {
268         /* we handle only button 3 press/release events */
269
270         switch (event->type) {
271         case GDK_BUTTON_PRESS:
272                 clicked_regionview = rv;
273                 clicked_control_point = 0;
274                 clicked_trackview = &rv->get_time_axis_view();
275                 clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
276                 if (event->button.button == 3) {
277                         return button_press_handler (item, event, FadeInItem);
278                 }
279                 break;
280
281         case GDK_BUTTON_RELEASE:
282                 if (event->button.button == 3) {
283                         return button_release_handler (item, event, FadeInItem);
284                 }
285                 break;
286
287         default:
288                 break;
289                 
290         }
291
292         /* proxy for the regionview */
293         
294         return canvas_region_view_event (event, rv->get_canvas_group(), rv);
295 }
296
297 bool
298 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
299 {
300         bool ret = false;
301         
302         switch (event->type) {
303         case GDK_BUTTON_PRESS:
304         case GDK_2BUTTON_PRESS:
305         case GDK_3BUTTON_PRESS:
306                 clicked_regionview = rv;
307                 clicked_control_point = 0;
308                 clicked_trackview = &rv->get_time_axis_view();
309                 clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
310                 ret = button_press_handler (item, event, FadeInHandleItem);
311                 break;
312
313         case GDK_BUTTON_RELEASE:
314                 ret = button_release_handler (item, event, FadeInHandleItem);
315                 break;
316
317         case GDK_MOTION_NOTIFY:
318                 ret = motion_handler (item, event, FadeInHandleItem);
319                 break;
320
321         case GDK_ENTER_NOTIFY:
322                 ret = enter_handler (item, event, FadeInHandleItem);
323                 break;
324
325         case GDK_LEAVE_NOTIFY:
326                 ret = leave_handler (item, event, FadeInHandleItem);
327                 break;
328
329         default:
330                 break;
331         }
332
333         return ret;
334 }
335
336 bool
337 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
338 {
339         /* we handle only button 3 press/release events */
340
341         switch (event->type) {
342         case GDK_BUTTON_PRESS:
343                 clicked_regionview = rv;
344                 clicked_control_point = 0;
345                 clicked_trackview = &rv->get_time_axis_view();
346                 clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
347                 if (event->button.button == 3) {
348                         return button_press_handler (item, event, FadeOutItem);
349                 }
350                 break;
351
352         case GDK_BUTTON_RELEASE:
353                 if (event->button.button == 3) {
354                         return button_release_handler (item, event, FadeOutItem);
355                 }
356                 break;
357
358         default:
359                 break;
360                 
361         }
362
363         /* proxy for the regionview */
364         
365         return canvas_region_view_event (event, rv->get_canvas_group(), rv);
366 }
367
368 bool
369 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
370 {
371         bool ret = false;
372         
373         switch (event->type) {
374         case GDK_BUTTON_PRESS:
375         case GDK_2BUTTON_PRESS:
376         case GDK_3BUTTON_PRESS:
377                 clicked_regionview = rv;
378                 clicked_control_point = 0;
379                 clicked_trackview = &rv->get_time_axis_view();
380                 clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
381                 ret = button_press_handler (item, event, FadeOutHandleItem);
382                 break;
383
384         case GDK_BUTTON_RELEASE:
385                 ret = button_release_handler (item, event, FadeOutHandleItem);
386                 break;
387
388         case GDK_MOTION_NOTIFY:
389                 ret = motion_handler (item, event, FadeOutHandleItem);
390                 break;
391
392         case GDK_ENTER_NOTIFY:
393                 ret = enter_handler (item, event, FadeOutHandleItem);
394                 break;
395
396         case GDK_LEAVE_NOTIFY:
397                 ret = leave_handler (item, event, FadeOutHandleItem);
398                 break;
399
400         default:
401                 break;
402         }
403
404         return ret;
405 }
406
407 struct DescendingRegionLayerSorter {
408     bool operator()(Region* a, Region* b) {
409             return a->layer() > b->layer();
410     }
411 };
412
413 bool
414 Editor::canvas_crossfade_view_event (GdkEvent* event, ArdourCanvas::Item* item, CrossfadeView* xfv)
415 {
416         /* we handle only button 3 press/release events */
417
418         switch (event->type) {
419         case GDK_BUTTON_PRESS:
420                 clicked_crossfadeview = xfv;
421                 clicked_trackview = &clicked_crossfadeview->get_time_axis_view();
422                 if (event->button.button == 3) {
423                         return button_press_handler (item, event, CrossfadeViewItem);
424                 } 
425                 break;
426
427         case GDK_BUTTON_RELEASE:
428                 if (event->button.button == 3) {
429                         bool ret = button_release_handler (item, event, CrossfadeViewItem);
430                         return ret;
431                 }
432                 break;
433
434         default:
435                 break;
436                 
437         }
438
439         
440         /* proxy for the upper most regionview */
441
442         /* XXX really need to check if we are in the name highlight,
443            and proxy to that when required.
444         */
445         
446         TimeAxisView& tv (xfv->get_time_axis_view());
447         AudioTimeAxisView* atv;
448
449         if ((atv = dynamic_cast<AudioTimeAxisView*>(&tv)) != 0) {
450
451                 if (atv->is_audio_track()) {
452                         
453                         AudioPlaylist* pl = atv->get_diskstream()->playlist();
454                         Playlist::RegionList* rl = pl->regions_at (event_frame (event));
455
456                         if (!rl->empty()) {
457                                 DescendingRegionLayerSorter cmp;
458                                 rl->sort (cmp);
459
460                                 AudioRegionView* arv = atv->view->find_view (*(dynamic_cast<AudioRegion*> (rl->front())));
461
462                                 /* proxy */
463                                 
464                                 delete rl;
465
466                                 return canvas_region_view_event (event, arv->get_canvas_group(), arv);
467                         } 
468                 }
469         }
470
471         return TRUE;
472 }
473
474 bool
475 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
476 {
477         ItemType type;
478
479         switch (event->type) {
480         case GDK_BUTTON_PRESS:
481         case GDK_2BUTTON_PRESS:
482         case GDK_3BUTTON_PRESS:
483                 clicked_control_point = cp;
484                 clicked_trackview = &cp->line.trackview;
485                 clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
486                 clicked_regionview = 0;
487                 break;
488
489         default:
490                 break;
491         }
492
493         if (dynamic_cast<AudioRegionGainLine*> (&cp->line) != 0) {
494                 type = GainControlPointItem;
495         } else if (dynamic_cast<AutomationGainLine*> (&cp->line) != 0) {
496                 type = GainAutomationControlPointItem;
497         } else if (dynamic_cast<AutomationPanLine*> (&cp->line) != 0) {
498                 type = PanAutomationControlPointItem;
499         } else if (dynamic_cast<RedirectAutomationLine*> (&cp->line) != 0) {
500                 type = RedirectAutomationControlPointItem;
501         } else {
502                 return false;
503         }
504
505         return typed_event (item, event, type);
506 }
507
508 bool
509 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
510 {
511         ItemType type;
512
513         if (dynamic_cast<AudioRegionGainLine*> (al) != 0) {
514                 type = GainLineItem;
515         } else if (dynamic_cast<AutomationGainLine*> (al) != 0) {
516                 type = GainAutomationLineItem;
517         } else if (dynamic_cast<AutomationPanLine*> (al) != 0) {
518                 type = PanAutomationLineItem;
519         } else if (dynamic_cast<RedirectAutomationLine*> (al) != 0) {
520                 type = RedirectAutomationLineItem;
521         } else {
522                 return false;
523         }
524
525         return typed_event (item, event, type);
526 }
527
528 bool
529 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
530 {
531         bool ret = false;
532         
533         switch (event->type) {
534         case GDK_BUTTON_PRESS:
535         case GDK_2BUTTON_PRESS:
536         case GDK_3BUTTON_PRESS:
537                 clicked_selection = rect->id;
538                 ret = button_press_handler (item, event, SelectionItem);
539                 break;
540         case GDK_BUTTON_RELEASE:
541                 ret = button_release_handler (item, event, SelectionItem);
542                 break;
543         case GDK_MOTION_NOTIFY:
544                 ret = motion_handler (item, event, SelectionItem);
545                 break;
546                 /* Don't need these at the moment. */
547         case GDK_ENTER_NOTIFY:
548                 ret = enter_handler (item, event, SelectionItem);
549                 break;
550
551         case GDK_LEAVE_NOTIFY:
552                 ret = leave_handler (item, event, SelectionItem);
553                 break;
554
555         default:
556                 break;
557         }
558                         
559         return ret;
560 }
561
562 bool
563 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
564 {
565         bool ret = false;
566
567         switch (event->type) {
568         case GDK_BUTTON_PRESS:
569         case GDK_2BUTTON_PRESS:
570         case GDK_3BUTTON_PRESS:
571                 clicked_selection = rect->id;
572                 ret = button_press_handler (item, event, StartSelectionTrimItem);
573                 break;
574         case GDK_BUTTON_RELEASE:
575                 ret = button_release_handler (item, event, StartSelectionTrimItem);
576                 break;
577         case GDK_MOTION_NOTIFY:
578                 ret = motion_handler (item, event, StartSelectionTrimItem);
579                 break;
580         case GDK_ENTER_NOTIFY:
581                 ret = enter_handler (item, event, StartSelectionTrimItem);
582                 break;
583
584         case GDK_LEAVE_NOTIFY:
585                 ret = leave_handler (item, event, StartSelectionTrimItem);
586                 break;
587
588         default:
589                 break;
590         }
591                         
592         return ret;
593 }
594
595 bool
596 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
597 {
598         bool ret = false;
599
600         switch (event->type) {
601         case GDK_BUTTON_PRESS:
602         case GDK_2BUTTON_PRESS:
603         case GDK_3BUTTON_PRESS:
604                 clicked_selection = rect->id;
605                 ret = button_press_handler (item, event, EndSelectionTrimItem);
606                 break;
607         case GDK_BUTTON_RELEASE:
608                 ret = button_release_handler (item, event, EndSelectionTrimItem);
609                 break;
610         case GDK_MOTION_NOTIFY:
611                 ret = motion_handler (item, event, EndSelectionTrimItem);
612                 break;
613         case GDK_ENTER_NOTIFY:
614                 ret = enter_handler (item, event, EndSelectionTrimItem);
615                 break;
616
617         case GDK_LEAVE_NOTIFY:
618                 ret = leave_handler (item, event, EndSelectionTrimItem);
619                 break;
620
621         default:
622                 break;
623         }
624                         
625         return ret;
626 }
627
628
629 bool
630 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, AudioRegionView* rv)
631 {
632         bool ret = false;
633         
634         switch (event->type) {
635         case GDK_BUTTON_PRESS:
636         case GDK_2BUTTON_PRESS:
637         case GDK_3BUTTON_PRESS:
638                 clicked_regionview = rv;
639                 clicked_control_point = 0;
640                 clicked_trackview = &clicked_regionview->get_time_axis_view();
641                 clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
642                 ret = button_press_handler (item, event, AudioRegionViewNameHighlight);
643                 break;
644         case GDK_BUTTON_RELEASE:
645                 ret = button_release_handler (item, event, AudioRegionViewNameHighlight);
646                 break;
647         case GDK_MOTION_NOTIFY:
648                 ret = motion_handler (item, event, AudioRegionViewNameHighlight);
649                 break;
650         case GDK_ENTER_NOTIFY:
651                 ret = enter_handler (item, event, AudioRegionViewNameHighlight);
652                 break;
653
654         case GDK_LEAVE_NOTIFY:
655                 ret = leave_handler (item, event, AudioRegionViewNameHighlight);
656                 break;
657
658         default:
659                 break;
660         }
661
662         return ret;
663 }
664
665 bool
666 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView* rv)
667 {
668         bool ret = false;
669
670         switch (event->type) {
671         case GDK_BUTTON_PRESS:
672         case GDK_2BUTTON_PRESS:
673         case GDK_3BUTTON_PRESS:
674                 clicked_regionview = rv;
675                 clicked_control_point = 0;
676                 clicked_trackview = &clicked_regionview->get_time_axis_view();
677                 clicked_audio_trackview = dynamic_cast<AudioTimeAxisView*>(clicked_trackview);
678                 ret = button_press_handler (item, event, AudioRegionViewName);
679                 break;
680         case GDK_BUTTON_RELEASE:
681                 ret = button_release_handler (item, event, AudioRegionViewName);
682                 break;
683         case GDK_MOTION_NOTIFY:
684                 ret = motion_handler (item, event, AudioRegionViewName);
685                 break;
686         case GDK_ENTER_NOTIFY:
687                 ret = enter_handler (item, event, AudioRegionViewName);
688                 break;
689
690         case GDK_LEAVE_NOTIFY:
691                 ret = leave_handler (item, event, AudioRegionViewName);
692                 break;
693
694         default:
695                 break;
696         }
697
698         return ret;
699 }
700
701 bool
702 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, Marker* marker)
703 {
704         return typed_event (item, event, MarkerItem);
705 }
706
707 bool
708 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
709 {
710         return typed_event (item, event, MarkerBarItem);
711 }
712
713 bool
714 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
715 {
716         return typed_event (item, event, RangeMarkerBarItem);
717 }
718
719 bool
720 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
721 {
722         return typed_event (item, event, TransportMarkerBarItem);
723 }
724
725 bool
726 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* marker)
727 {
728         return typed_event (item, event, TempoMarkerItem);
729 }
730
731 bool
732 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* marker)
733 {
734         return typed_event (item, event, MeterMarkerItem);
735 }
736
737 bool
738 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
739 {
740         return typed_event (item, event, TempoBarItem);
741 }
742
743 bool
744 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
745 {
746         return typed_event (item, event, MeterBarItem);
747 }
748
749 bool
750 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
751 {
752         return typed_event (item, event, PlayheadCursorItem);
753 }
754
755 bool
756 Editor::canvas_edit_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
757 {
758         return typed_event (item, event, EditCursorItem);
759 }
760
761 bool
762 Editor::canvas_zoom_rect_event (GdkEvent *event, ArdourCanvas::Item* item)
763 {
764         return typed_event (item, event, NoItem);
765 }
766