1 /*
2 * Copyright (C) 2005-2018 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com>
4 * Copyright (C) 2006-2012 David Robillard <d@drobilla.net>
5 * Copyright (C) 2008 Hans Baier <hansfbaier@googlemail.com>
6 * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
7 * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
8 * Copyright (C) 2015-2016 Tim Mayberry <mojofunk@gmail.com>
9 * Copyright (C) 2015-2017 Nick Mainsbridge <mainsbridge@gmail.com>
10 * Copyright (C) 2015-2019 Ben Loftis <ben@harrisonconsoles.com>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
27 #include <cstdlib>
28 #include <cmath>
29 #include <algorithm>
30 #include <typeinfo>
31
32 #include "ardour/audio_track.h"
33 #include "ardour/midi_track.h"
34 #include "ardour/midi_region.h"
35 #include "ardour/profile.h"
36 #include "ardour/region_factory.h"
37
38 #include "canvas/canvas.h"
39 #include "canvas/text.h"
40 #include "canvas/scroll_group.h"
41
42 #include "editor.h"
43 #include "keyboard.h"
44 #include "public_editor.h"
45 #include "audio_region_view.h"
46 #include "audio_streamview.h"
47 #include "audio_time_axis.h"
48 #include "region_gain_line.h"
49 #include "automation_line.h"
50 #include "automation_time_axis.h"
51 #include "automation_line.h"
52 #include "control_point.h"
53 #include "editor_drag.h"
54 #include "midi_time_axis.h"
55 #include "editor_regions.h"
56 #include "editor_sources.h"
57 #include "ui_config.h"
58 #include "verbose_cursor.h"
59
60 #include "pbd/i18n.h"
61
62 using namespace std;
63 using namespace ARDOUR;
64 using namespace PBD;
65 using namespace Gtk;
66 using namespace ArdourCanvas;
67
68 using Gtkmm2ext::Keyboard;
69
70 bool
track_canvas_scroll(GdkEventScroll * ev)71 Editor::track_canvas_scroll (GdkEventScroll* ev)
72 {
73 int direction = ev->direction;
74
75 /* this event arrives without transformation by the canvas, so we have
76 * to transform the coordinates to be able to look things up.
77 */
78
79 Duple event_coords = _track_canvas->window_to_canvas (Duple (ev->x, ev->y));
80
81 switch (direction) {
82 case GDK_SCROLL_UP:
83 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
84 temporal_zoom_step_mouse_focus (false);
85 return true;
86 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
87 scroll_left_step ();
88 return true;
89 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
90 if (!current_stepping_trackview) {
91 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
92 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
93 current_stepping_trackview = p.first;
94 if (!current_stepping_trackview) {
95 return false;
96 }
97 }
98 last_track_height_step_timestamp = get_microseconds();
99 current_stepping_trackview->step_height (false);
100 return true;
101 } else {
102 scroll_up_one_track ();
103 return true;
104 }
105 break;
106
107 case GDK_SCROLL_DOWN:
108 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomHorizontalModifier)) {
109 temporal_zoom_step_mouse_focus (true);
110 return true;
111 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollHorizontalModifier)) {
112 scroll_right_step ();
113 return true;
114 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
115 if (!current_stepping_trackview) {
116 step_timeout = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Editor::track_height_step_timeout), 500);
117 std::pair<TimeAxisView*, int> const p = trackview_by_y_position (event_coords.y, false);
118 current_stepping_trackview = p.first;
119 if (!current_stepping_trackview) {
120 return false;
121 }
122 }
123 last_track_height_step_timestamp = get_microseconds();
124 current_stepping_trackview->step_height (true);
125 return true;
126 } else {
127 scroll_down_one_track ();
128 return true;
129 }
130 break;
131
132 case GDK_SCROLL_LEFT:
133 scroll_left_step ();
134 return true;
135 break;
136
137 case GDK_SCROLL_RIGHT:
138 scroll_right_step ();
139 return true;
140 break;
141
142 default:
143 /* what? */
144 break;
145 }
146
147 return false;
148 }
149
150 bool
canvas_scroll_event(GdkEventScroll * event,bool from_canvas)151 Editor::canvas_scroll_event (GdkEventScroll *event, bool from_canvas)
152 {
153 if (from_canvas) {
154 boost::optional<ArdourCanvas::Rect> rulers = _time_markers_group->bounding_box();
155 if (rulers && rulers->contains (Duple (event->x, event->y))) {
156 return canvas_ruler_event ((GdkEvent*) event, timecode_ruler, TimecodeRulerItem);
157 }
158 }
159
160 _track_canvas->grab_focus();
161 return track_canvas_scroll (event);
162 }
163
164 bool
track_canvas_button_press_event(GdkEventButton * event)165 Editor::track_canvas_button_press_event (GdkEventButton *event)
166 {
167 _track_canvas->grab_focus();
168 if (!internal_editing() && !Keyboard::is_context_menu_event (event)) {
169 begin_reversible_selection_op (X_("Clear Selection Click (track canvas)"));
170 selection->clear ();
171 commit_reversible_selection_op();
172 }
173 return false;
174 }
175
176 bool
track_canvas_button_release_event(GdkEventButton * event)177 Editor::track_canvas_button_release_event (GdkEventButton *event)
178 {
179 if (!Keyboard::is_context_menu_event (event)) {
180 if (_drags->active ()) {
181
182 GdkEvent copy = *((GdkEvent*) event);
183 Duple winpos = Duple (event->x, event->y);
184 Duple where = _track_canvas->window_to_canvas (winpos);
185
186 copy.button.x = where.x;
187 copy.button.y = where.y;
188
189 _drags->end_grab (©);
190 }
191 }
192 return false;
193 }
194
195 bool
track_canvas_motion_notify_event(GdkEventMotion *)196 Editor::track_canvas_motion_notify_event (GdkEventMotion */*event*/)
197 {
198 int x, y;
199 /* keep those motion events coming */
200 _track_canvas->get_pointer (x, y);
201 return false;
202 }
203
204 bool
typed_event(ArdourCanvas::Item * item,GdkEvent * event,ItemType type)205 Editor::typed_event (ArdourCanvas::Item* item, GdkEvent *event, ItemType type)
206 {
207 if (!session () || session()->loading () || session()->deletion_in_progress ()) {
208 return false;
209 }
210
211 gint ret = FALSE;
212
213 switch (event->type) {
214 case GDK_BUTTON_PRESS:
215 case GDK_2BUTTON_PRESS:
216 case GDK_3BUTTON_PRESS:
217 ret = button_press_handler (item, event, type);
218 break;
219 case GDK_BUTTON_RELEASE:
220 ret = button_release_handler (item, event, type);
221 break;
222 case GDK_MOTION_NOTIFY:
223 ret = motion_handler (item, event);
224 break;
225
226 case GDK_ENTER_NOTIFY:
227 ret = enter_handler (item, event, type);
228 break;
229
230 case GDK_LEAVE_NOTIFY:
231 ret = leave_handler (item, event, type);
232 break;
233
234 case GDK_KEY_PRESS:
235 ret = key_press_handler (item, event, type);
236 break;
237
238 case GDK_KEY_RELEASE:
239 ret = key_release_handler (item, event, type);
240 break;
241
242 default:
243 break;
244 }
245 return ret;
246 }
247
248 bool
canvas_region_view_event(GdkEvent * event,ArdourCanvas::Item * item,RegionView * rv)249 Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView *rv)
250 {
251 bool ret = false;
252
253 if (!rv->sensitive ()) {
254 return false;
255 }
256
257 switch (event->type) {
258 case GDK_BUTTON_PRESS:
259 case GDK_2BUTTON_PRESS:
260 case GDK_3BUTTON_PRESS:
261 clicked_regionview = rv;
262 clicked_control_point = 0;
263 clicked_axisview = &rv->get_time_axis_view();
264 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
265 ret = button_press_handler (item, event, RegionItem);
266 break;
267
268 case GDK_BUTTON_RELEASE:
269 ret = button_release_handler (item, event, RegionItem);
270 break;
271
272 case GDK_MOTION_NOTIFY:
273 ret = motion_handler (item, event);
274 break;
275
276 case GDK_ENTER_NOTIFY:
277 set_entered_regionview (rv);
278 ret = enter_handler (item, event, RegionItem);
279 break;
280
281 case GDK_LEAVE_NOTIFY:
282 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
283 set_entered_regionview (0);
284 ret = leave_handler (item, event, RegionItem);
285 }
286 break;
287
288 default:
289 break;
290 }
291
292 return ret;
293 }
294
295 bool
canvas_wave_view_event(GdkEvent * event,ArdourCanvas::Item * item,RegionView * rv)296 Editor::canvas_wave_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
297 {
298 /* we only care about enter events here, required for mouse/cursor
299 * tracking. there is a non-linear (non-child/non-parent) relationship
300 * between various components of a regionview and so when we leave one
301 * of them (e.g. a trim handle) and enter another (e.g. the waveview)
302 * no other items get notified. enter/leave handling does not propagate
303 * in the same way as other events, so we need to catch this because
304 * entering (and leaving) the waveview is equivalent to
305 * entering/leaving the regionview (which is why it is passed in as a
306 * third argument).
307 *
308 * And in fact, we really only care about enter events.
309 */
310
311 bool ret = false;
312
313 if (!rv->sensitive ()) {
314 return false;
315 }
316
317 switch (event->type) {
318 case GDK_ENTER_NOTIFY:
319 set_entered_regionview (rv);
320 ret = enter_handler (item, event, WaveItem);
321 break;
322
323 default:
324 break;
325 }
326
327 return ret;
328 }
329
330
331 bool
canvas_stream_view_event(GdkEvent * event,ArdourCanvas::Item * item,RouteTimeAxisView * tv)332 Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv)
333 {
334 bool ret = FALSE;
335
336 switch (event->type) {
337 case GDK_BUTTON_PRESS:
338 case GDK_2BUTTON_PRESS:
339 case GDK_3BUTTON_PRESS:
340 clicked_regionview = 0;
341 clicked_control_point = 0;
342 clicked_axisview = tv;
343 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
344 ret = button_press_handler (item, event, StreamItem);
345 break;
346
347 case GDK_BUTTON_RELEASE:
348 ret = button_release_handler (item, event, StreamItem);
349 break;
350
351 case GDK_MOTION_NOTIFY:
352 ret = motion_handler (item, event);
353 break;
354
355 case GDK_ENTER_NOTIFY:
356 set_entered_track (tv);
357 ret = enter_handler (item, event, StreamItem);
358 break;
359
360 case GDK_LEAVE_NOTIFY:
361 if (event->crossing.detail != GDK_NOTIFY_INFERIOR) {
362 set_entered_track (0);
363 }
364 ret = leave_handler (item, event, StreamItem);
365 break;
366
367 default:
368 break;
369 }
370
371 return ret;
372 }
373
374 bool
canvas_automation_track_event(GdkEvent * event,ArdourCanvas::Item * item,AutomationTimeAxisView * atv)375 Editor::canvas_automation_track_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationTimeAxisView *atv)
376 {
377 bool ret = false;
378
379 switch (event->type) {
380 case GDK_BUTTON_PRESS:
381 case GDK_2BUTTON_PRESS:
382 case GDK_3BUTTON_PRESS:
383 clicked_regionview = 0;
384 clicked_control_point = 0;
385 clicked_axisview = atv;
386 clicked_routeview = 0;
387 ret = button_press_handler (item, event, AutomationTrackItem);
388 break;
389
390 case GDK_BUTTON_RELEASE:
391 ret = button_release_handler (item, event, AutomationTrackItem);
392 break;
393
394 case GDK_MOTION_NOTIFY:
395 ret = motion_handler (item, event);
396 break;
397
398 case GDK_ENTER_NOTIFY:
399 ret = enter_handler (item, event, AutomationTrackItem);
400 break;
401
402 case GDK_LEAVE_NOTIFY:
403 ret = leave_handler (item, event, AutomationTrackItem);
404 break;
405
406 default:
407 break;
408 }
409
410 return ret;
411 }
412
413 bool
canvas_start_xfade_event(GdkEvent * event,ArdourCanvas::Item * item,AudioRegionView * rv)414 Editor::canvas_start_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
415 {
416 if (!rv->sensitive()) {
417 return false;
418 }
419
420 switch (event->type) {
421 case GDK_BUTTON_PRESS:
422 clicked_regionview = rv;
423 clicked_control_point = 0;
424 clicked_axisview = &rv->get_time_axis_view();
425 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
426 if (event->button.button == 3) {
427 return button_press_handler (item, event, StartCrossFadeItem);
428 }
429 break;
430
431 case GDK_BUTTON_RELEASE:
432 if (event->button.button == 3) {
433 return button_release_handler (item, event, StartCrossFadeItem);
434 }
435 break;
436
437 default:
438 break;
439
440 }
441
442 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
443 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
444 /* if we return RegionItem here then we avoid the issue until it is resolved later */
445 return typed_event (item, event, RegionItem); // StartCrossFadeItem);
446 }
447
448 bool
canvas_end_xfade_event(GdkEvent * event,ArdourCanvas::Item * item,AudioRegionView * rv)449 Editor::canvas_end_xfade_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
450 {
451 if (!rv->sensitive()) {
452 return false;
453 }
454
455 switch (event->type) {
456 case GDK_BUTTON_PRESS:
457 clicked_regionview = rv;
458 clicked_control_point = 0;
459 clicked_axisview = &rv->get_time_axis_view();
460 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
461 if (event->button.button == 3) {
462 return button_press_handler (item, event, EndCrossFadeItem);
463 }
464 break;
465
466 case GDK_BUTTON_RELEASE:
467 if (event->button.button == 3) {
468 return button_release_handler (item, event, EndCrossFadeItem);
469 }
470 break;
471
472 default:
473 break;
474
475 }
476
477 /* In Mixbus, the crossfade area is used to trim the region while leaving the fade anchor intact (see preserve_fade_anchor)*/
478 /* however in A3 this feature is unfinished, and it might be better to do it with a modifier-trim instead, anyway */
479 /* if we return RegionItem here then we avoid the issue until it is resolved later */
480 return typed_event (item, event, RegionItem); // EndCrossFadeItem);
481 }
482
483 bool
canvas_fade_in_event(GdkEvent * event,ArdourCanvas::Item * item,AudioRegionView * rv)484 Editor::canvas_fade_in_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
485 {
486 /* we handle only button 3 press/release events */
487
488 if (!rv->sensitive()) {
489 return false;
490 }
491
492 switch (event->type) {
493 case GDK_BUTTON_PRESS:
494 clicked_regionview = rv;
495 clicked_control_point = 0;
496 clicked_axisview = &rv->get_time_axis_view();
497 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
498 if (event->button.button == 3) {
499 return button_press_handler (item, event, FadeInItem);
500 }
501 break;
502
503 case GDK_BUTTON_RELEASE:
504 if (event->button.button == 3) {
505 return button_release_handler (item, event, FadeInItem);
506 }
507 break;
508
509 default:
510 break;
511
512 }
513
514 /* proxy for the regionview, except enter/leave events */
515
516 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
517 return true;
518 } else {
519 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
520 }
521 }
522
523 bool
canvas_fade_in_handle_event(GdkEvent * event,ArdourCanvas::Item * item,AudioRegionView * rv,bool trim)524 Editor::canvas_fade_in_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
525 {
526 bool ret = false;
527
528 if (!rv->sensitive()) {
529 return false;
530 }
531
532 switch (event->type) {
533 case GDK_BUTTON_PRESS:
534 case GDK_2BUTTON_PRESS:
535 case GDK_3BUTTON_PRESS:
536 clicked_regionview = rv;
537 clicked_control_point = 0;
538 clicked_axisview = &rv->get_time_axis_view();
539 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
540 ret = button_press_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
541 break;
542
543 case GDK_BUTTON_RELEASE:
544 ret = button_release_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
545 break;
546
547 case GDK_MOTION_NOTIFY:
548 ret = motion_handler (item, event);
549 break;
550
551 case GDK_ENTER_NOTIFY:
552 ret = enter_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
553 break;
554
555 case GDK_LEAVE_NOTIFY:
556 ret = leave_handler (item, event, trim ? FadeInTrimHandleItem : FadeInHandleItem);
557 break;
558
559 default:
560 break;
561 }
562
563 return ret;
564 }
565
566 bool
canvas_fade_out_event(GdkEvent * event,ArdourCanvas::Item * item,AudioRegionView * rv)567 Editor::canvas_fade_out_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv)
568 {
569 /* we handle only button 3 press/release events */
570
571 if (!rv->sensitive()) {
572 return false;
573 }
574
575 switch (event->type) {
576 case GDK_BUTTON_PRESS:
577 clicked_regionview = rv;
578 clicked_control_point = 0;
579 clicked_axisview = &rv->get_time_axis_view();
580 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
581 if (event->button.button == 3) {
582 return button_press_handler (item, event, FadeOutItem);
583 }
584 break;
585
586 case GDK_BUTTON_RELEASE:
587 if (event->button.button == 3) {
588 return button_release_handler (item, event, FadeOutItem);
589 }
590 break;
591
592 default:
593 break;
594
595 }
596
597 /* proxy for the regionview, except enter/leave events */
598
599 if (event->type == GDK_ENTER_NOTIFY || event->type == GDK_LEAVE_NOTIFY) {
600 return true;
601 } else {
602 return canvas_region_view_event (event, rv->get_canvas_group(), rv);
603 }
604 }
605
606 bool
canvas_fade_out_handle_event(GdkEvent * event,ArdourCanvas::Item * item,AudioRegionView * rv,bool trim)607 Editor::canvas_fade_out_handle_event (GdkEvent *event, ArdourCanvas::Item* item, AudioRegionView *rv, bool trim)
608 {
609 bool ret = false;
610
611 if (!rv->sensitive()) {
612 return false;
613 }
614
615 switch (event->type) {
616 case GDK_BUTTON_PRESS:
617 case GDK_2BUTTON_PRESS:
618 case GDK_3BUTTON_PRESS:
619 clicked_regionview = rv;
620 clicked_control_point = 0;
621 clicked_axisview = &rv->get_time_axis_view();
622 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
623 ret = button_press_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
624 break;
625
626 case GDK_BUTTON_RELEASE:
627 ret = button_release_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
628 break;
629
630 case GDK_MOTION_NOTIFY:
631 ret = motion_handler (item, event);
632 break;
633
634 case GDK_ENTER_NOTIFY:
635 ret = enter_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
636 break;
637
638 case GDK_LEAVE_NOTIFY:
639 ret = leave_handler (item, event, trim ? FadeOutTrimHandleItem : FadeOutHandleItem);
640 break;
641
642 default:
643 break;
644 }
645
646 return ret;
647 }
648
649 struct DescendingRegionLayerSorter {
operator ()DescendingRegionLayerSorter650 bool operator()(boost::shared_ptr<Region> a, boost::shared_ptr<Region> b) {
651 return a->layer() > b->layer();
652 }
653 };
654
655 bool
canvas_control_point_event(GdkEvent * event,ArdourCanvas::Item * item,ControlPoint * cp)656 Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
657 {
658 switch (event->type) {
659 case GDK_BUTTON_PRESS:
660 case GDK_2BUTTON_PRESS:
661 case GDK_3BUTTON_PRESS:
662 clicked_control_point = cp;
663 clicked_axisview = &cp->line().trackview;
664 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
665 clicked_regionview = 0;
666 break;
667 default:
668 break;
669 }
670
671 return typed_event (item, event, ControlPointItem);
672 }
673
674 bool
canvas_line_event(GdkEvent * event,ArdourCanvas::Item * item,AutomationLine * al)675 Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
676 {
677 ItemType type;
678 AudioRegionGainLine* gl;
679 if ((gl = dynamic_cast<AudioRegionGainLine*> (al)) != 0) {
680 type = GainLineItem;
681 if (event->type == GDK_BUTTON_PRESS) {
682 clicked_regionview = &gl->region_view ();
683 }
684 } else {
685 type = AutomationLineItem;
686 if (event->type == GDK_BUTTON_PRESS) {
687 clicked_regionview = 0;
688 }
689 }
690
691 clicked_control_point = 0;
692 clicked_axisview = &al->trackview;
693 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
694
695 return typed_event (item, event, type);
696 }
697
698 bool
canvas_selection_rect_event(GdkEvent * event,ArdourCanvas::Item * item,SelectionRect * rect)699 Editor::canvas_selection_rect_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
700 {
701 bool ret = false;
702
703 switch (event->type) {
704 case GDK_BUTTON_PRESS:
705 case GDK_2BUTTON_PRESS:
706 case GDK_3BUTTON_PRESS:
707 clicked_selection = rect->id;
708 ret = button_press_handler (item, event, SelectionItem);
709 break;
710 case GDK_BUTTON_RELEASE:
711 ret = button_release_handler (item, event, SelectionItem);
712 break;
713 case GDK_MOTION_NOTIFY:
714 ret = motion_handler (item, event);
715 break;
716 /* Don't need these at the moment. */
717 case GDK_ENTER_NOTIFY:
718 ret = enter_handler (item, event, SelectionItem);
719 break;
720
721 case GDK_LEAVE_NOTIFY:
722 ret = leave_handler (item, event, SelectionItem);
723 break;
724
725 default:
726 break;
727 }
728
729 return ret;
730 }
731
732 bool
canvas_selection_start_trim_event(GdkEvent * event,ArdourCanvas::Item * item,SelectionRect * rect)733 Editor::canvas_selection_start_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
734 {
735 bool ret = false;
736
737 switch (event->type) {
738 case GDK_BUTTON_PRESS:
739 case GDK_2BUTTON_PRESS:
740 case GDK_3BUTTON_PRESS:
741 clicked_selection = rect->id;
742 ret = button_press_handler (item, event, StartSelectionTrimItem);
743 break;
744 case GDK_BUTTON_RELEASE:
745 ret = button_release_handler (item, event, StartSelectionTrimItem);
746 break;
747 case GDK_MOTION_NOTIFY:
748 ret = motion_handler (item, event);
749 break;
750 case GDK_ENTER_NOTIFY:
751 ret = enter_handler (item, event, StartSelectionTrimItem);
752 break;
753
754 case GDK_LEAVE_NOTIFY:
755 ret = leave_handler (item, event, StartSelectionTrimItem);
756 break;
757
758 default:
759 break;
760 }
761
762 return ret;
763 }
764
765 bool
canvas_selection_end_trim_event(GdkEvent * event,ArdourCanvas::Item * item,SelectionRect * rect)766 Editor::canvas_selection_end_trim_event (GdkEvent *event, ArdourCanvas::Item* item, SelectionRect* rect)
767 {
768 bool ret = false;
769
770 switch (event->type) {
771 case GDK_BUTTON_PRESS:
772 case GDK_2BUTTON_PRESS:
773 case GDK_3BUTTON_PRESS:
774 clicked_selection = rect->id;
775 ret = button_press_handler (item, event, EndSelectionTrimItem);
776 break;
777 case GDK_BUTTON_RELEASE:
778 ret = button_release_handler (item, event, EndSelectionTrimItem);
779 break;
780 case GDK_MOTION_NOTIFY:
781 ret = motion_handler (item, event);
782 break;
783 case GDK_ENTER_NOTIFY:
784 ret = enter_handler (item, event, EndSelectionTrimItem);
785 break;
786
787 case GDK_LEAVE_NOTIFY:
788 ret = leave_handler (item, event, EndSelectionTrimItem);
789 break;
790
791 default:
792 break;
793 }
794
795 return ret;
796 }
797
798 bool
canvas_frame_handle_event(GdkEvent * event,ArdourCanvas::Item * item,RegionView * rv)799 Editor::canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
800 {
801 bool ret = false;
802
803 /* frame handles are not active when in internal edit mode, because actual notes
804 might be in the area occupied by the handle - we want them to be editable as normal.
805 */
806
807 if (internal_editing() || !rv->sensitive()) {
808 return false;
809 }
810
811 /* NOTE: frame handles pretend to be the colored trim bar from an event handling
812 perspective. XXX change this ??
813 */
814
815 ItemType type;
816
817 if (item->get_data ("isleft")) {
818 type = LeftFrameHandle;
819 } else {
820 type = RightFrameHandle;
821 }
822
823 switch (event->type) {
824 case GDK_BUTTON_PRESS:
825 case GDK_2BUTTON_PRESS:
826 case GDK_3BUTTON_PRESS:
827 clicked_regionview = rv;
828 clicked_control_point = 0;
829 clicked_axisview = &clicked_regionview->get_time_axis_view();
830 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
831 ret = button_press_handler (item, event, type);
832 break;
833 case GDK_BUTTON_RELEASE:
834 ret = button_release_handler (item, event, type);
835 break;
836 case GDK_MOTION_NOTIFY:
837 ret = motion_handler (item, event);
838 break;
839 case GDK_ENTER_NOTIFY:
840 ret = enter_handler (item, event, type);
841 break;
842
843 case GDK_LEAVE_NOTIFY:
844 ret = leave_handler (item, event, type);
845 break;
846
847 default:
848 break;
849 }
850
851 return ret;
852 }
853
854
855 bool
canvas_region_view_name_highlight_event(GdkEvent * event,ArdourCanvas::Item * item,RegionView * rv)856 Editor::canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item* item, RegionView* rv)
857 {
858 bool ret = false;
859
860 if (!rv->sensitive()) {
861 return false;
862 }
863
864 switch (event->type) {
865 case GDK_BUTTON_PRESS:
866 case GDK_2BUTTON_PRESS:
867 case GDK_3BUTTON_PRESS:
868 clicked_regionview = rv;
869 clicked_control_point = 0;
870 clicked_axisview = &clicked_regionview->get_time_axis_view();
871 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
872 ret = button_press_handler (item, event, RegionViewNameHighlight);
873 break;
874 case GDK_BUTTON_RELEASE:
875 ret = button_release_handler (item, event, RegionViewNameHighlight);
876 break;
877 case GDK_MOTION_NOTIFY:
878 motion_handler (item, event);
879 ret = true; // force this to avoid progagating the event into the regionview
880 break;
881 case GDK_ENTER_NOTIFY:
882 ret = enter_handler (item, event, RegionViewNameHighlight);
883 break;
884
885 case GDK_LEAVE_NOTIFY:
886 ret = leave_handler (item, event, RegionViewNameHighlight);
887 break;
888
889 default:
890 break;
891 }
892
893 return ret;
894 }
895
896 bool
canvas_region_view_name_event(GdkEvent * event,ArdourCanvas::Item * item,RegionView * rv)897 Editor::canvas_region_view_name_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv)
898 {
899 bool ret = false;
900
901 if (!rv->sensitive()) {
902 return false;
903 }
904
905 switch (event->type) {
906 case GDK_BUTTON_PRESS:
907 case GDK_2BUTTON_PRESS:
908 case GDK_3BUTTON_PRESS:
909 clicked_regionview = rv;
910 clicked_control_point = 0;
911 clicked_axisview = &clicked_regionview->get_time_axis_view();
912 clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
913 ret = button_press_handler (item, event, RegionViewName);
914 break;
915 case GDK_BUTTON_RELEASE:
916 ret = button_release_handler (item, event, RegionViewName);
917 break;
918 case GDK_MOTION_NOTIFY:
919 ret = motion_handler (item, event);
920 break;
921 case GDK_ENTER_NOTIFY:
922 ret = enter_handler (item, event, RegionViewName);
923 break;
924
925 case GDK_LEAVE_NOTIFY:
926 ret = leave_handler (item, event, RegionViewName);
927 break;
928
929 default:
930 break;
931 }
932
933 return ret;
934 }
935
936 bool
canvas_feature_line_event(GdkEvent * event,ArdourCanvas::Item * item,RegionView *)937 Editor::canvas_feature_line_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView*)
938 {
939 bool ret = false;
940
941 switch (event->type) {
942 case GDK_BUTTON_PRESS:
943 case GDK_2BUTTON_PRESS:
944 case GDK_3BUTTON_PRESS:
945 clicked_regionview = 0;
946 clicked_control_point = 0;
947 clicked_axisview = 0;
948 clicked_routeview = 0; //dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
949 ret = button_press_handler (item, event, FeatureLineItem);
950 break;
951
952 case GDK_BUTTON_RELEASE:
953 ret = button_release_handler (item, event, FeatureLineItem);
954 break;
955
956 case GDK_MOTION_NOTIFY:
957 ret = motion_handler (item, event);
958 break;
959
960 case GDK_ENTER_NOTIFY:
961 ret = enter_handler (item, event, FeatureLineItem);
962 break;
963
964 case GDK_LEAVE_NOTIFY:
965 ret = leave_handler (item, event, FeatureLineItem);
966 break;
967
968 default:
969 break;
970 }
971
972 return ret;
973 }
974
975 bool
canvas_marker_event(GdkEvent * event,ArdourCanvas::Item * item,ArdourMarker *)976 Editor::canvas_marker_event (GdkEvent *event, ArdourCanvas::Item* item, ArdourMarker* /*marker*/)
977 {
978 return typed_event (item, event, MarkerItem);
979 }
980
981 bool
canvas_marker_bar_event(GdkEvent * event,ArdourCanvas::Item * item)982 Editor::canvas_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
983 {
984 return typed_event (item, event, MarkerBarItem);
985 }
986
987 bool
canvas_range_marker_bar_event(GdkEvent * event,ArdourCanvas::Item * item)988 Editor::canvas_range_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
989 {
990 return typed_event (item, event, RangeMarkerBarItem);
991 }
992
993 bool
canvas_transport_marker_bar_event(GdkEvent * event,ArdourCanvas::Item * item)994 Editor::canvas_transport_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
995 {
996 return typed_event (item, event, TransportMarkerBarItem);
997 }
998
999 bool
canvas_cd_marker_bar_event(GdkEvent * event,ArdourCanvas::Item * item)1000 Editor::canvas_cd_marker_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1001 {
1002 return typed_event (item, event, CdMarkerBarItem);
1003 }
1004
1005 bool
canvas_videotl_bar_event(GdkEvent * event,ArdourCanvas::Item * item)1006 Editor::canvas_videotl_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1007 {
1008 return typed_event (item, event, VideoBarItem);
1009 }
1010
1011 bool
canvas_tempo_marker_event(GdkEvent * event,ArdourCanvas::Item * item,TempoMarker * marker)1012 Editor::canvas_tempo_marker_event (GdkEvent *event, ArdourCanvas::Item* item, TempoMarker* marker)
1013 {
1014 return typed_event (item, event, TempoMarkerItem);
1015 }
1016
1017 bool
canvas_tempo_curve_event(GdkEvent * event,ArdourCanvas::Item * item,TempoCurve *)1018 Editor::canvas_tempo_curve_event (GdkEvent *event, ArdourCanvas::Item* item, TempoCurve* /*marker*/)
1019 {
1020 return typed_event (item, event, TempoCurveItem);
1021 }
1022
1023 bool
canvas_meter_marker_event(GdkEvent * event,ArdourCanvas::Item * item,MeterMarker *)1024 Editor::canvas_meter_marker_event (GdkEvent *event, ArdourCanvas::Item* item, MeterMarker* /*marker*/)
1025 {
1026 return typed_event (item, event, MeterMarkerItem);
1027 }
1028
1029 bool
canvas_ruler_event(GdkEvent * event,ArdourCanvas::Item * item,ItemType type)1030 Editor::canvas_ruler_event (GdkEvent *event, ArdourCanvas::Item* item, ItemType type)
1031 {
1032 bool handled = false;
1033
1034 if (event->type == GDK_SCROLL) {
1035
1036 /* scroll events in the rulers are handled a little differently from
1037 scrolling elsewhere in the canvas.
1038 */
1039
1040 switch (event->scroll.direction) {
1041 case GDK_SCROLL_UP:
1042 if (Keyboard::modifier_state_equals (event->scroll.state, Keyboard::ScrollHorizontalModifier)) {
1043 scroll_left_step ();
1044 } else if (UIConfiguration::instance().get_use_mouse_position_as_zoom_focus_on_scroll()) {
1045 temporal_zoom_step_mouse_focus (false);
1046 } else if (Keyboard::modifier_state_equals (event->scroll.state, Keyboard::PrimaryModifier)) {
1047 temporal_zoom_step_mouse_focus (false);
1048 } else {
1049 temporal_zoom_step (false);
1050 }
1051 handled = true;
1052 break;
1053
1054 case GDK_SCROLL_DOWN:
1055 if (Keyboard::modifier_state_equals (event->scroll.state, Keyboard::ScrollHorizontalModifier)) {
1056 scroll_right_step ();
1057 } else if (UIConfiguration::instance().get_use_mouse_position_as_zoom_focus_on_scroll()) {
1058 temporal_zoom_step_mouse_focus (true);
1059 } else if (Keyboard::modifier_state_equals (event->scroll.state, Keyboard::PrimaryModifier)) {
1060 temporal_zoom_step_mouse_focus (true);
1061 } else {
1062 temporal_zoom_step (true);
1063 }
1064 handled = true;
1065 break;
1066
1067 case GDK_SCROLL_LEFT:
1068 scroll_left_half_page ();
1069 handled = true;
1070 break;
1071
1072 case GDK_SCROLL_RIGHT:
1073 scroll_right_half_page ();
1074 handled = true;
1075 break;
1076
1077 default:
1078 /* what? */
1079 break;
1080 }
1081 return handled;
1082 }
1083
1084 return typed_event (item, event, type);
1085 }
1086
1087 bool
canvas_tempo_bar_event(GdkEvent * event,ArdourCanvas::Item * item)1088 Editor::canvas_tempo_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1089 {
1090 return typed_event (item, event, TempoBarItem);
1091 }
1092
1093 bool
canvas_meter_bar_event(GdkEvent * event,ArdourCanvas::Item * item)1094 Editor::canvas_meter_bar_event (GdkEvent *event, ArdourCanvas::Item* item)
1095 {
1096 return typed_event (item, event, MeterBarItem);
1097 }
1098
1099 bool
canvas_playhead_cursor_event(GdkEvent * event,ArdourCanvas::Item * item)1100 Editor::canvas_playhead_cursor_event (GdkEvent *event, ArdourCanvas::Item* item)
1101 {
1102 return typed_event (item, event, PlayheadCursorItem);
1103 }
1104
1105 bool
canvas_note_event(GdkEvent * event,ArdourCanvas::Item * item)1106 Editor::canvas_note_event (GdkEvent *event, ArdourCanvas::Item* item)
1107 {
1108 if (!internal_editing()) {
1109 return false;
1110 }
1111
1112 return typed_event (item, event, NoteItem);
1113 }
1114
1115 bool
canvas_drop_zone_event(GdkEvent * event)1116 Editor::canvas_drop_zone_event (GdkEvent* event)
1117 {
1118 GdkEventScroll scroll;
1119 ArdourCanvas::Duple winpos;
1120
1121 switch (event->type) {
1122 case GDK_BUTTON_RELEASE:
1123 if (event->button.button == 1) {
1124 begin_reversible_selection_op (X_("Nowhere Click"));
1125 selection->clear_objects ();
1126 selection->clear_tracks ();
1127 commit_reversible_selection_op ();
1128 }
1129 break;
1130
1131 case GDK_SCROLL:
1132 /* convert coordinates back into window space so that
1133 we can just call canvas_scroll_event().
1134 */
1135 winpos = _track_canvas->canvas_to_window (Duple (event->scroll.x, event->scroll.y));
1136 scroll = event->scroll;
1137 scroll.x = winpos.x;
1138 scroll.y = winpos.y;
1139 return canvas_scroll_event (&scroll, true);
1140 break;
1141
1142 case GDK_ENTER_NOTIFY:
1143 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1144
1145 case GDK_LEAVE_NOTIFY:
1146 return typed_event (_canvas_drop_zone, event, DropZoneItem);
1147
1148 default:
1149 break;
1150 }
1151
1152 return true;
1153 }
1154
1155 bool
track_canvas_drag_motion(Glib::RefPtr<Gdk::DragContext> const & context,int x,int y,guint time)1156 Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const& context, int x, int y, guint time)
1157 {
1158 boost::shared_ptr<Region> region;
1159 boost::shared_ptr<Region> region_copy;
1160 RouteTimeAxisView* rtav;
1161 GdkEvent event;
1162 double px;
1163 double py;
1164
1165 string target = _track_canvas->drag_dest_find_target (context, _track_canvas->drag_dest_get_target_list());
1166
1167 if (target.empty()) {
1168 return false;
1169 }
1170
1171 event.type = GDK_MOTION_NOTIFY;
1172 event.button.x = x;
1173 event.button.y = y;
1174 /* assume we're dragging with button 1 */
1175 event.motion.state = Gdk::BUTTON1_MASK;
1176
1177 (void) window_event_sample (&event, &px, &py);
1178
1179 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1180 bool can_drop = false;
1181
1182 if (tv.first != 0) {
1183
1184 /* over a time axis view of some kind */
1185
1186 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1187
1188 if (rtav != 0 && rtav->is_track ()) {
1189 /* over a track, not a bus */
1190 can_drop = true;
1191 }
1192
1193
1194 } else {
1195 /* not over a time axis view, so drop is possible */
1196 can_drop = true;
1197 }
1198
1199 if (can_drop) {
1200
1201 if (target == X_("regions")) {
1202 region = _regions->get_dragged_region ();
1203 }
1204
1205 if (region) {
1206
1207 if (tv.first == 0
1208 && (
1209 boost::dynamic_pointer_cast<AudioRegion> (region) != 0 ||
1210 boost::dynamic_pointer_cast<MidiRegion> (region) != 0
1211 )
1212 )
1213 {
1214 /* drop to drop-zone */
1215 context->drag_status (context->get_suggested_action(), time);
1216 return true;
1217 }
1218
1219 if ((boost::dynamic_pointer_cast<AudioRegion> (region) != 0 &&
1220 dynamic_cast<AudioTimeAxisView*> (tv.first) != 0) ||
1221 (boost::dynamic_pointer_cast<MidiRegion> (region) != 0 &&
1222 dynamic_cast<MidiTimeAxisView*> (tv.first) != 0)) {
1223
1224 /* audio to audio
1225 OR
1226 midi to midi
1227 */
1228
1229 context->drag_status (context->get_suggested_action(), time);
1230 return true;
1231 }
1232 } else {
1233 /* DND originating from outside ardour
1234 *
1235 * TODO: check if file is audio/midi, allow drops on same track-type only,
1236 * currently: if audio is dropped on a midi-track, it is only added to the region-list
1237 */
1238 if (UIConfiguration::instance().get_only_copy_imported_files()) {
1239 context->drag_status(Gdk::ACTION_COPY, time);
1240 } else {
1241 if ((context->get_actions() & (Gdk::ACTION_COPY | Gdk::ACTION_LINK | Gdk::ACTION_MOVE)) == Gdk::ACTION_COPY) {
1242 context->drag_status(Gdk::ACTION_COPY, time);
1243 } else {
1244 context->drag_status(Gdk::ACTION_LINK, time);
1245 }
1246 }
1247 return true;
1248 }
1249 }
1250
1251 /* no drop here */
1252 context->drag_status (Gdk::DragAction (0), time);
1253 return false;
1254 }
1255
1256 void
drop_regions(const Glib::RefPtr<Gdk::DragContext> &,int x,int y,const SelectionData &,guint,guint,bool from_region_list)1257 Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
1258 int x, int y,
1259 const SelectionData& /*data*/,
1260 guint /*info*/, guint /*time*/,
1261 bool from_region_list)
1262 {
1263 GdkEvent event;
1264 double px;
1265 double py;
1266
1267 event.type = GDK_MOTION_NOTIFY;
1268 event.button.x = x;
1269 event.button.y = y;
1270 /* assume we're dragging with button 1 */
1271 event.motion.state = Gdk::BUTTON1_MASK;
1272 samplepos_t const pos = window_event_sample (&event, &px, &py);
1273
1274 boost::shared_ptr<Region> region;
1275
1276 if (from_region_list) {
1277 region = _regions->get_dragged_region ();
1278 } else {
1279 region = _sources->get_dragged_region ();
1280 }
1281
1282 if (!region) { return; }
1283
1284 RouteTimeAxisView* rtav = 0;
1285 std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py, false);
1286
1287 if (tv.first != 0) {
1288 rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
1289 } else {
1290 try {
1291 if (boost::dynamic_pointer_cast<AudioRegion> (region)) {
1292 uint32_t output_chan = region->n_channels();
1293 if ((Config->get_output_auto_connect() & AutoConnectMaster) && session()->master_out()) {
1294 output_chan = session()->master_out()->n_inputs().n_audio();
1295 }
1296 list<boost::shared_ptr<AudioTrack> > audio_tracks;
1297 audio_tracks = session()->new_audio_track (region->n_channels(), output_chan, 0, 1, region->name(), PresentationInfo::max_order);
1298 rtav = dynamic_cast<RouteTimeAxisView*> (time_axis_view_from_stripable (audio_tracks.front()));
1299 } else if (boost::dynamic_pointer_cast<MidiRegion> (region)) {
1300 ChanCount one_midi_port (DataType::MIDI, 1);
1301 list<boost::shared_ptr<MidiTrack> > midi_tracks;
1302 midi_tracks = session()->new_midi_track (one_midi_port, one_midi_port,
1303 Config->get_strict_io () || Profile->get_mixbus (),
1304 boost::shared_ptr<ARDOUR::PluginInfo>(),
1305 (ARDOUR::Plugin::PresetRecord*) 0,
1306 (ARDOUR::RouteGroup*) 0, 1, region->name(), PresentationInfo::max_order);
1307 rtav = dynamic_cast<RouteTimeAxisView*> (time_axis_view_from_stripable (midi_tracks.front()));
1308 } else {
1309 return;
1310 }
1311 } catch (...) {
1312 error << _("Could not create new track after region placed in the drop zone") << endmsg;
1313 return;
1314 }
1315 }
1316
1317 if (rtav != 0 && rtav->is_track ()) {
1318 boost::shared_ptr<Region> region_copy = RegionFactory::create (region, true);
1319
1320 if ((boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 && dynamic_cast<AudioTimeAxisView*> (rtav) != 0) ||
1321 (boost::dynamic_pointer_cast<MidiRegion> (region_copy) != 0 && dynamic_cast<MidiTimeAxisView*> (rtav) != 0)) {
1322 _drags->set (new RegionInsertDrag (this, region_copy, rtav, pos), &event);
1323 _drags->end_grab (&event);
1324 }
1325 }
1326 }
1327
1328 bool
key_press_handler(ArdourCanvas::Item *,GdkEvent *,ItemType)1329 Editor::key_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType)
1330 {
1331 return false;
1332 }
1333
1334 bool
key_release_handler(ArdourCanvas::Item * item,GdkEvent * event,ItemType type)1335 Editor::key_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType type)
1336 {
1337
1338 bool handled = false;
1339
1340 switch (type) {
1341 case TempoMarkerItem:
1342 switch (event->key.keyval) {
1343 case GDK_Delete:
1344 remove_tempo_marker (item);
1345 handled = true;
1346 break;
1347 default:
1348 break;
1349 }
1350 break;
1351
1352 case MeterMarkerItem:
1353 switch (event->key.keyval) {
1354 case GDK_Delete:
1355 remove_meter_marker (item);
1356 handled = true;
1357 break;
1358 default:
1359 break;
1360 }
1361 break;
1362
1363 default:
1364 break;
1365 }
1366
1367 return handled;
1368 }
1369