Merge branch 'master' into cairocanvas
[ardour.git] / gtk2_ardour / editor_markers.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 */
19
20 #include <cstdlib>
21 #include <cmath>
22
23 #include <gtkmm2ext/gtk_ui.h>
24
25 #include "ardour/session.h"
26 #include "ardour/location.h"
27 #include "ardour/profile.h"
28 #include "pbd/memento_command.h"
29
30 #include "canvas/canvas.h"
31 #include "canvas/item.h"
32 #include "canvas/rectangle.h"
33
34 #include "editor.h"
35 #include "marker.h"
36 #include "selection.h"
37 #include "editing.h"
38 #include "gui_thread.h"
39 #include "actions.h"
40 #include "prompter.h"
41 #include "editor_drag.h"
42
43 #include "i18n.h"
44
45 using namespace std;
46 using namespace ARDOUR;
47 using namespace PBD;
48 using namespace Gtk;
49 using namespace Gtkmm2ext;
50
51 void
52 Editor::clear_marker_display ()
53 {
54         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
55                 delete i->second;
56         }
57
58         location_markers.clear ();
59         _sorted_marker_lists.clear ();
60 }
61
62 void
63 Editor::add_new_location (Location *location)
64 {
65         ENSURE_GUI_THREAD (*this, &Editor::add_new_location, location);
66
67         ArdourCanvas::Group* group = add_new_location_internal (location);
68
69         /* Do a full update of the markers in this group */
70         update_marker_labels (group);
71         
72         if (location->is_auto_punch()) {
73                 update_punch_range_view ();
74         }
75
76         if (location->is_auto_loop()) {
77                 update_loop_range_view ();
78         }
79 }
80
81 /** Add a new location, without a time-consuming update of all marker labels;
82  *  the caller must call update_marker_labels () after calling this.
83  *  @return canvas group that the location's marker was added to.
84  */
85 ArdourCanvas::Group*
86 Editor::add_new_location_internal (Location* location)
87 {
88         LocationMarkers *lam = new LocationMarkers;
89         uint32_t color;
90
91         /* make a note here of which group this marker ends up in */
92         ArdourCanvas::Group* group = 0;
93
94         if (location->is_cd_marker()) {
95                 color = location_cd_marker_color;
96         } else if (location->is_mark()) {
97                 color = location_marker_color;
98         } else if (location->is_auto_loop()) {
99                 color = location_loop_color;
100         } else if (location->is_auto_punch()) {
101                 color = location_punch_color;
102         } else {
103                 color = location_range_color;
104         }
105
106         if (location->is_mark()) {
107
108                 if (location->is_cd_marker() && ruler_cd_marker_action->get_active()) {
109                         lam->start = new Marker (*this, *cd_marker_group, color, location->name(), Marker::Mark, location->start());
110                         group = cd_marker_group;
111                 } else {
112                         lam->start = new Marker (*this, *marker_group, color, location->name(), Marker::Mark, location->start());
113                         group = marker_group;
114                 }
115
116                 lam->end = 0;
117
118         } else if (location->is_auto_loop()) {
119
120                 // transport marker
121                 lam->start = new Marker (*this, *transport_marker_group, color,
122                                          location->name(), Marker::LoopStart, location->start());
123                 lam->end   = new Marker (*this, *transport_marker_group, color,
124                                          location->name(), Marker::LoopEnd, location->end());
125                 group = transport_marker_group;
126
127         } else if (location->is_auto_punch()) {
128
129                 // transport marker
130                 lam->start = new Marker (*this, *transport_marker_group, color,
131                                          location->name(), Marker::PunchIn, location->start());
132                 lam->end   = new Marker (*this, *transport_marker_group, color,
133                                          location->name(), Marker::PunchOut, location->end());
134                 group = transport_marker_group;
135
136         } else if (location->is_session_range()) {
137
138                 // session range
139                 lam->start = new Marker (*this, *marker_group, color, _("start"), Marker::SessionStart, location->start());
140                 lam->end = new Marker (*this, *marker_group, color, _("end"), Marker::SessionEnd, location->end());
141                 group = marker_group;
142
143         } else {
144                 // range marker
145                 if (location->is_cd_marker() && ruler_cd_marker_action->get_active()) {
146                         lam->start = new Marker (*this, *cd_marker_group, color,
147                                                  location->name(), Marker::RangeStart, location->start());
148                         lam->end   = new Marker (*this, *cd_marker_group, color,
149                                                  location->name(), Marker::RangeEnd, location->end());
150                         group = cd_marker_group;
151                 } else {
152                         lam->start = new Marker (*this, *range_marker_group, color,
153                                                  location->name(), Marker::RangeStart, location->start());
154                         lam->end   = new Marker (*this, *range_marker_group, color,
155                                                  location->name(), Marker::RangeEnd, location->end());
156                         group = range_marker_group;
157                 }
158         }
159
160         if (location->is_hidden ()) {
161                 lam->hide();
162         } else {
163                 lam->show ();
164         }
165
166         location->start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
167         location->end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
168         location->changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
169         location->name_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
170         location->FlagsChanged.connect (*this, invalidator (*this), boost::bind (&Editor::location_flags_changed, this, _1, _2), gui_context());
171
172         pair<Location*,LocationMarkers*> newpair;
173
174         newpair.first = location;
175         newpair.second = lam;
176
177         location_markers.insert (newpair);
178
179         if (select_new_marker && location->is_mark()) {
180                 selection->set (lam->start);
181                 select_new_marker = false;
182         }
183
184         lam->canvas_height_set (_visible_canvas_height);
185         lam->set_show_lines (_show_marker_lines);
186
187         /* Add these markers to the appropriate sorted marker lists, which will render
188            them unsorted until a call to update_marker_labels() sorts them out.
189         */
190         _sorted_marker_lists[group].push_back (lam->start);
191         if (lam->end) {
192                 _sorted_marker_lists[group].push_back (lam->end);
193         }
194
195         return group;
196 }
197
198 void
199 Editor::location_changed (Location *location)
200 {
201         ENSURE_GUI_THREAD (*this, &Editor::location_changed, location)
202
203         LocationMarkers *lam = find_location_markers (location);
204
205         if (lam == 0) {
206                 /* a location that isn't "marked" with markers */
207                 return;
208         }
209
210         lam->set_name (location->name ());
211         lam->set_position (location->start(), location->end());
212
213         if (location->is_auto_loop()) {
214                 update_loop_range_view ();
215         } else if (location->is_auto_punch()) {
216                 update_punch_range_view ();
217         }
218
219         check_marker_label (lam->start);
220         if (lam->end) {
221                 check_marker_label (lam->end);
222         }
223 }
224
225 /** Look at a marker and check whether its label, and those of the previous and next markers,
226  *  need to have their labels updated (in case those labels need to be shortened or can be
227  *  lengthened)
228  */
229 void
230 Editor::check_marker_label (Marker* m)
231 {
232         /* Get a time-ordered list of markers from the last time anything changed */
233         std::list<Marker*>& sorted = _sorted_marker_lists[m->get_parent()];
234
235         list<Marker*>::iterator i = find (sorted.begin(), sorted.end(), m);
236
237         list<Marker*>::iterator prev = sorted.end ();
238         list<Marker*>::iterator next = i;
239         ++next;
240
241         /* Look to see if the previous marker is still behind `m' in time */
242         if (i != sorted.begin()) {
243
244                 prev = i;
245                 --prev;
246
247                 if ((*prev)->position() > m->position()) {
248                         /* This marker is no longer in the correct order with the previous one, so
249                          * update all the markers in this group.
250                          */
251                         update_marker_labels (m->get_parent ());
252                         return;
253                 }
254         }
255
256         /* Look to see if the next marker is still ahead of `m' in time */
257         if (next != sorted.end() && (*next)->position() < m->position()) {
258                 /* This marker is no longer in the correct order with the next one, so
259                  * update all the markers in this group.
260                  */
261                 update_marker_labels (m->get_parent ());
262                 return;
263         }
264
265         if (prev != sorted.end()) {
266
267                 /* Update just the available space between the previous marker and this one */
268
269                 double const p = sample_to_pixel (m->position() - (*prev)->position());
270
271                 if (m->label_on_left()) {
272                         (*prev)->set_right_label_limit (p / 2);
273                 } else {
274                         (*prev)->set_right_label_limit (p);
275                 }
276
277                 if ((*prev)->label_on_left ()) {
278                         m->set_left_label_limit (p);
279                 } else {
280                         m->set_left_label_limit (p / 2);
281                 }
282         }
283
284         if (next != sorted.end()) {
285
286                 /* Update just the available space between this marker and the next */
287
288                 double const p = sample_to_pixel ((*next)->position() - m->position());
289
290                 if ((*next)->label_on_left()) {
291                         m->set_right_label_limit (p / 2);
292                 } else {
293                         m->set_right_label_limit (p);
294                 }
295
296                 if (m->label_on_left()) {
297                         (*next)->set_left_label_limit (p);
298                 } else {
299                         (*next)->set_left_label_limit (p / 2);
300                 }
301         }
302 }
303
304 struct MarkerComparator {
305         bool operator() (Marker const * a, Marker const * b) {
306                 return a->position() < b->position();
307         }
308 };
309
310 /** Update all marker labels in all groups */
311 void
312 Editor::update_marker_labels ()
313 {
314         for (std::map<ArdourCanvas::Group *, std::list<Marker *> >::iterator i = _sorted_marker_lists.begin(); i != _sorted_marker_lists.end(); ++i) {
315                 update_marker_labels (i->first);
316         }
317 }
318
319 /** Look at all markers in a group and update label widths */
320 void
321 Editor::update_marker_labels (ArdourCanvas::Group* group)
322 {
323         list<Marker*>& sorted = _sorted_marker_lists[group];
324
325         if (sorted.empty()) {
326                 return;
327         }
328
329         /* We sort the list of markers and then set up the space available between each one */
330
331         sorted.sort (MarkerComparator ());
332
333         list<Marker*>::iterator i = sorted.begin ();
334
335         list<Marker*>::iterator prev = sorted.end ();
336         list<Marker*>::iterator next = i;
337         ++next;
338
339         while (i != sorted.end()) {
340
341                 if (prev != sorted.end()) {
342                         double const p = sample_to_pixel ((*i)->position() - (*prev)->position());
343
344                         if ((*prev)->label_on_left()) {
345                                 (*i)->set_left_label_limit (p);
346                         } else {
347                                 (*i)->set_left_label_limit (p / 2);
348                         }
349
350                 }
351
352                 if (next != sorted.end()) {
353                         double const p = sample_to_pixel ((*next)->position() - (*i)->position());
354
355                         if ((*next)->label_on_left()) {
356                                 (*i)->set_right_label_limit (p / 2);
357                         } else {
358                                 (*i)->set_right_label_limit (p);
359                         }
360                 }
361
362                 prev = i;
363                 ++i;
364                 ++next;
365         }
366 }
367
368 void
369 Editor::location_flags_changed (Location *location, void*)
370 {
371         ENSURE_GUI_THREAD (*this, &Editor::location_flags_changed, location, src)
372
373         LocationMarkers *lam = find_location_markers (location);
374
375         if (lam == 0) {
376                 /* a location that isn't "marked" with markers */
377                 return;
378         }
379
380         // move cd markers to/from cd marker bar as appropriate
381         ensure_cd_marker_updated (lam, location);
382
383         if (location->is_cd_marker()) {
384                 lam->set_color_rgba (location_cd_marker_color);
385         } else if (location->is_mark()) {
386                 lam->set_color_rgba (location_marker_color);
387         } else if (location->is_auto_punch()) {
388                 lam->set_color_rgba (location_punch_color);
389         } else if (location->is_auto_loop()) {
390                 lam->set_color_rgba (location_loop_color);
391         } else {
392                 lam->set_color_rgba (location_range_color);
393         }
394
395         if (location->is_hidden()) {
396                 lam->hide();
397         } else {
398                 lam->show ();
399         }
400 }
401
402 void Editor::update_cd_marker_display ()
403 {
404         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
405                 LocationMarkers * lam = i->second;
406                 Location * location = i->first;
407
408                 ensure_cd_marker_updated (lam, location);
409         }
410 }
411
412 void Editor::ensure_cd_marker_updated (LocationMarkers * lam, Location * location)
413 {
414         if (location->is_cd_marker()
415             && (ruler_cd_marker_action->get_active() &&  lam->start->get_parent() != cd_marker_group))
416         {
417                 //cerr << "reparenting non-cd marker so it can be relocated: " << location->name() << endl;
418                 if (lam->start) {
419                         lam->start->reparent (*cd_marker_group);
420                 }
421                 if (lam->end) {
422                         lam->end->reparent (*cd_marker_group);
423                 }
424         }
425         else if ( (!location->is_cd_marker() || !ruler_cd_marker_action->get_active())
426                   && (lam->start->get_parent() == cd_marker_group))
427         {
428                 //cerr << "reparenting non-cd marker so it can be relocated: " << location->name() << endl;
429                 if (location->is_mark()) {
430                         if (lam->start) {
431                                 lam->start->reparent (*marker_group);
432                         }
433                         if (lam->end) {
434                                 lam->end->reparent (*marker_group);
435                         }
436                 }
437                 else {
438                         if (lam->start) {
439                                 lam->start->reparent (*range_marker_group);
440                         }
441                         if (lam->end) {
442                                 lam->end->reparent (*range_marker_group);
443                         }
444                 }
445         }
446 }
447
448 Editor::LocationMarkers::~LocationMarkers ()
449 {
450         delete start;
451         delete end;
452 }
453
454 Editor::LocationMarkers *
455 Editor::find_location_markers (Location *location) const
456 {
457         LocationMarkerMap::const_iterator i;
458
459         for (i = location_markers.begin(); i != location_markers.end(); ++i) {
460                 if ((*i).first == location) {
461                         return (*i).second;
462                 }
463         }
464
465         return 0;
466 }
467
468 Location *
469 Editor::find_location_from_marker (Marker *marker, bool& is_start) const
470 {
471         LocationMarkerMap::const_iterator i;
472
473         for (i = location_markers.begin(); i != location_markers.end(); ++i) {
474                 LocationMarkers *lm = (*i).second;
475                 if (lm->start == marker) {
476                         is_start = true;
477                         return (*i).first;
478                 } else if (lm->end == marker) {
479                         is_start = false;
480                         return (*i).first;
481                 }
482         }
483
484         return 0;
485 }
486
487 void
488 Editor::refresh_location_display_internal (Locations::LocationList& locations)
489 {
490         /* invalidate all */
491
492         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
493                 i->second->valid = false;
494         }
495
496         /* add new ones */
497
498         for (Locations::LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
499
500                 LocationMarkerMap::iterator x;
501
502                 if ((x = location_markers.find (*i)) != location_markers.end()) {
503                         x->second->valid = true;
504                         continue;
505                 }
506
507                 add_new_location_internal (*i);
508         }
509
510         /* remove dead ones */
511
512         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ) {
513
514                 LocationMarkerMap::iterator tmp;
515
516                 tmp = i;
517                 ++tmp;
518
519                 if (!i->second->valid) {
520
521                         remove_sorted_marker (i->second->start);
522                         if (i->second->end) {
523                                 remove_sorted_marker (i->second->end);
524                         }
525
526                         LocationMarkers* m = i->second;
527                         location_markers.erase (i);
528                         delete m;
529                 }
530
531                 i = tmp;
532         }
533
534         update_punch_range_view ();
535         update_loop_range_view ();
536 }
537
538 void
539 Editor::refresh_location_display ()
540 {
541         ENSURE_GUI_THREAD (*this, &Editor::refresh_location_display)
542
543         if (_session) {
544                 _session->locations()->apply (*this, &Editor::refresh_location_display_internal);
545         }
546
547         update_marker_labels ();
548 }
549
550 void
551 Editor::LocationMarkers::hide()
552 {
553         start->hide ();
554         if (end) {
555                 end->hide ();
556         }
557 }
558
559 void
560 Editor::LocationMarkers::show()
561 {
562         start->show ();
563         if (end) {
564                 end->show ();
565         }
566 }
567
568 void
569 Editor::LocationMarkers::canvas_height_set (double h)
570 {
571         start->canvas_height_set (h);
572         if (end) {
573                 end->canvas_height_set (h);
574         }
575 }
576
577 void
578 Editor::LocationMarkers::set_name (const string& str)
579 {
580         /* XXX: hack: don't change names of session start/end markers */
581
582         if (start->type() != Marker::SessionStart) {
583                 start->set_name (str);
584         }
585
586         if (end && end->type() != Marker::SessionEnd) {
587                 end->set_name (str);
588         }
589 }
590
591 void
592 Editor::LocationMarkers::set_position (framepos_t startf,
593                                        framepos_t endf)
594 {
595         start->set_position (startf);
596         if (end) {
597                 end->set_position (endf);
598         }
599 }
600
601 void
602 Editor::LocationMarkers::set_color_rgba (uint32_t rgba)
603 {
604         start->set_color_rgba (rgba);
605         if (end) {
606                 end->set_color_rgba (rgba);
607         }
608 }
609
610 void
611 Editor::LocationMarkers::set_show_lines (bool s)
612 {
613         start->set_show_line (s);
614         if (end) {
615                 end->set_show_line (s);
616         }
617 }
618
619 void
620 Editor::LocationMarkers::set_selected (bool s)
621 {
622         start->set_selected (s);
623         if (end) {
624                 end->set_selected (s);
625         }
626 }
627
628 void
629 Editor::LocationMarkers::setup_lines ()
630 {
631         start->setup_line ();
632         if (end) {
633                 end->setup_line ();
634         }
635 }
636
637 void
638 Editor::mouse_add_new_marker (framepos_t where, bool is_cd, bool is_xrun)
639 {
640         string markername, markerprefix;
641         int flags = (is_cd ? Location::IsCDMarker|Location::IsMark : Location::IsMark);
642
643         if (is_xrun) {
644                 markerprefix = "xrun";
645                 flags = Location::IsMark;
646         } else {
647                 markerprefix = "mark";
648         }
649
650         if (_session) {
651                 _session->locations()->next_available_name(markername, markerprefix);
652                 if (!is_xrun && !choose_new_marker_name(markername)) {
653                         return;
654                 }
655                 Location *location = new Location (*_session, where, where, markername, (Location::Flags) flags);
656                 _session->begin_reversible_command (_("add marker"));
657                 XMLNode &before = _session->locations()->get_state();
658                 _session->locations()->add (location, true);
659                 XMLNode &after = _session->locations()->get_state();
660                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
661                 _session->commit_reversible_command ();
662
663                 /* find the marker we just added */
664
665                 LocationMarkers *lam = find_location_markers (location);
666                 if (lam) {
667                         /* make it the selected marker */
668                         selection->set (lam->start);
669                 }
670         }
671 }
672
673 void
674 Editor::mouse_add_new_range (framepos_t where)
675 {
676         if (!_session) {
677                 return;
678         }
679
680         /* Make this marker 1/8th of the visible area of the session so that
681            it's reasonably easy to manipulate after creation.
682         */
683
684         framepos_t const end = where + current_page_samples() / 8;
685
686         string name;
687         _session->locations()->next_available_name (name, _("range"));
688         Location* loc = new Location (*_session, where, end, name, Location::IsRangeMarker);
689
690         begin_reversible_command (_("new range marker"));
691         XMLNode& before = _session->locations()->get_state ();
692         _session->locations()->add (loc, true);
693         XMLNode& after = _session->locations()->get_state ();
694         _session->add_command (new MementoCommand<Locations> (*_session->locations(), &before, &after));
695         commit_reversible_command ();
696 }
697
698 void
699 Editor::remove_marker (ArdourCanvas::Item& item, GdkEvent*)
700 {
701         Marker* marker;
702         bool is_start;
703
704         if ((marker = static_cast<Marker*> (item.get_data ("marker"))) == 0) {
705                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
706                 /*NOTREACHED*/
707         }
708
709         if (entered_marker == marker) {
710                 entered_marker = NULL;
711         }
712
713         Location* loc = find_location_from_marker (marker, is_start);
714
715         if (_session && loc) {
716                 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
717         }
718 }
719
720 gint
721 Editor::really_remove_marker (Location* loc)
722 {
723         _session->begin_reversible_command (_("remove marker"));
724         XMLNode &before = _session->locations()->get_state();
725         _session->locations()->remove (loc);
726         XMLNode &after = _session->locations()->get_state();
727         _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
728         _session->commit_reversible_command ();
729         return FALSE;
730 }
731
732 void
733 Editor::location_gone (Location *location)
734 {
735         ENSURE_GUI_THREAD (*this, &Editor::location_gone, location)
736
737         LocationMarkerMap::iterator i;
738
739         if (location == transport_loop_location()) {
740                 update_loop_range_view ();
741         }
742
743         if (location == transport_punch_location()) {
744                 update_punch_range_view ();
745         }
746
747         for (i = location_markers.begin(); i != location_markers.end(); ++i) {
748                 if (i->first == location) {
749
750                         remove_sorted_marker (i->second->start);
751                         if (i->second->end) {
752                                 remove_sorted_marker (i->second->end);
753                         }
754
755                         LocationMarkers* m = i->second;
756                         location_markers.erase (i);
757                         delete m;
758                         break;
759                 }
760         }
761 }
762
763 void
764 Editor::tempo_or_meter_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
765 {
766         marker_menu_item = item;
767
768         MeterMarker* mm;
769         TempoMarker* tm;
770         dynamic_cast_marker_object (marker_menu_item->get_data ("marker"), &mm, &tm);
771
772         bool can_remove = false;
773
774         if (mm) {
775                 can_remove = mm->meter().movable ();
776         } else if (tm) {
777                 can_remove = tm->tempo().movable ();
778         } else {
779                 return;
780         }
781
782         delete tempo_or_meter_marker_menu;
783         build_tempo_or_meter_marker_menu (can_remove);
784         tempo_or_meter_marker_menu->popup (1, ev->time);
785 }
786
787 void
788 Editor::marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
789 {
790         Marker * marker;
791         if ((marker = reinterpret_cast<Marker *> (item->get_data("marker"))) == 0) {
792                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
793                 /*NOTREACHED*/
794         }
795
796         bool is_start;
797         Location * loc = find_location_from_marker (marker, is_start);
798
799         if (loc == transport_loop_location() || loc == transport_punch_location() || loc->is_session_range ()) {
800
801                 if (transport_marker_menu == 0) {
802                         build_range_marker_menu (loc == transport_loop_location() || loc == transport_punch_location(), loc->is_session_range());
803                 }
804
805                 marker_menu_item = item;
806                 transport_marker_menu->popup (1, ev->time);
807
808         } else if (loc->is_mark()) {
809
810                         delete marker_menu;
811                         build_marker_menu (loc);
812
813                 // GTK2FIX use action group sensitivity
814 #ifdef GTK2FIX
815                         if (children.size() >= 3) {
816                                 MenuItem * loopitem = &children[2];
817                                 if (loopitem) {
818                                         if (loc->is_mark()) {
819                                                 loopitem->set_sensitive(false);
820                                         }
821                                         else {
822                                                 loopitem->set_sensitive(true);
823                                         }
824                                 }
825                         }
826 #endif
827                         marker_menu_item = item;
828                         marker_menu->popup (1, ev->time);
829
830         } else if (loc->is_range_marker()) {
831                 if (range_marker_menu == 0) {
832                         build_range_marker_menu (false, false);
833                 }
834                 marker_menu_item = item;
835                 range_marker_menu->popup (1, ev->time);
836         }
837 }
838
839 void
840 Editor::new_transport_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item*)
841 {
842         if (new_transport_marker_menu == 0) {
843                 build_new_transport_marker_menu ();
844         }
845
846         new_transport_marker_menu->popup (1, ev->time);
847
848 }
849
850 void
851 Editor::build_marker_menu (Location* loc)
852 {
853         using namespace Menu_Helpers;
854
855         marker_menu = new Menu;
856         MenuList& items = marker_menu->items();
857         marker_menu->set_name ("ArdourContextMenu");
858
859         items.push_back (MenuElem (_("Locate to Here"), sigc::mem_fun(*this, &Editor::marker_menu_set_playhead)));
860         items.push_back (MenuElem (_("Play from Here"), sigc::mem_fun(*this, &Editor::marker_menu_play_from)));
861         items.push_back (MenuElem (_("Move Mark to Playhead"), sigc::mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
862
863         items.push_back (SeparatorElem());
864
865         items.push_back (MenuElem (_("Create Range to Next Marker"), sigc::mem_fun(*this, &Editor::marker_menu_range_to_next)));
866
867         items.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &Editor::marker_menu_hide)));
868         items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &Editor::marker_menu_rename)));
869
870         items.push_back (CheckMenuElem (_("Lock")));
871         Gtk::CheckMenuItem* lock_item = static_cast<Gtk::CheckMenuItem*> (&items.back());
872         if (loc->locked ()) {
873                 lock_item->set_active ();
874         }
875         lock_item->signal_activate().connect (sigc::mem_fun (*this, &Editor::toggle_marker_menu_lock));
876
877         items.push_back (CheckMenuElem (_("Glue to Bars and Beats")));
878         Gtk::CheckMenuItem* glue_item = static_cast<Gtk::CheckMenuItem*> (&items.back());
879         if (loc->position_lock_style() == MusicTime) {
880                 glue_item->set_active ();
881         }
882         glue_item->signal_activate().connect (sigc::mem_fun (*this, &Editor::toggle_marker_menu_glue));
883
884         items.push_back (SeparatorElem());
885
886         items.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &Editor::marker_menu_remove)));
887 }
888
889 void
890 Editor::build_range_marker_menu (bool loop_or_punch, bool session)
891 {
892         using namespace Menu_Helpers;
893
894         bool const loop_or_punch_or_session = loop_or_punch | session;
895
896         Menu *markerMenu = new Menu;
897         if (loop_or_punch_or_session) {
898                 transport_marker_menu = markerMenu;
899         } else {
900                 range_marker_menu = markerMenu;
901         }
902         MenuList& items = markerMenu->items();
903         markerMenu->set_name ("ArdourContextMenu");
904
905         items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::marker_menu_play_range)));
906         items.push_back (MenuElem (_("Locate to Marker"), sigc::mem_fun(*this, &Editor::marker_menu_set_playhead)));
907         items.push_back (MenuElem (_("Play from Marker"), sigc::mem_fun(*this, &Editor::marker_menu_play_from)));
908         items.push_back (MenuElem (_("Loop Range"), sigc::mem_fun(*this, &Editor::marker_menu_loop_range)));
909
910         items.push_back (MenuElem (_("Set Marker from Playhead"), sigc::mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
911         if (!Profile->get_sae()) {
912                 items.push_back (MenuElem (_("Set Range from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::marker_menu_set_from_selection), false)));
913         }
914
915         items.push_back (MenuElem (_("Zoom to Range"), sigc::mem_fun (*this, &Editor::marker_menu_zoom_to_range)));
916
917         items.push_back (SeparatorElem());
918         items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_range)));
919         items.push_back (SeparatorElem());
920
921         if (!loop_or_punch_or_session) {
922                 items.push_back (MenuElem (_("Hide Range"), sigc::mem_fun(*this, &Editor::marker_menu_hide)));
923                 items.push_back (MenuElem (_("Rename Range..."), sigc::mem_fun(*this, &Editor::marker_menu_rename)));
924         }
925
926         if (!session) {
927                 items.push_back (MenuElem (_("Remove Range"), sigc::mem_fun(*this, &Editor::marker_menu_remove)));
928         }
929
930         if (!loop_or_punch_or_session || !session) {
931                 items.push_back (SeparatorElem());
932         }
933         
934         items.push_back (MenuElem (_("Separate Regions in Range"), sigc::mem_fun(*this, &Editor::marker_menu_separate_regions_using_location)));
935         items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::marker_menu_select_all_selectables_using_range)));
936         if (!Profile->get_sae()) {
937                 items.push_back (MenuElem (_("Select Range"), sigc::mem_fun(*this, &Editor::marker_menu_select_using_range)));
938         }
939 }
940
941 void
942 Editor::build_tempo_or_meter_marker_menu (bool can_remove)
943 {
944         using namespace Menu_Helpers;
945
946         tempo_or_meter_marker_menu = new Menu;
947         MenuList& items = tempo_or_meter_marker_menu->items();
948         tempo_or_meter_marker_menu->set_name ("ArdourContextMenu");
949
950         items.push_back (MenuElem (_("Edit..."), sigc::mem_fun(*this, &Editor::marker_menu_edit)));
951         items.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &Editor::marker_menu_remove)));
952
953         items.back().set_sensitive (can_remove);
954 }
955
956 void
957 Editor::build_new_transport_marker_menu ()
958 {
959         using namespace Menu_Helpers;
960
961         new_transport_marker_menu = new Menu;
962         MenuList& items = new_transport_marker_menu->items();
963         new_transport_marker_menu->set_name ("ArdourContextMenu");
964
965         items.push_back (MenuElem (_("Set Loop Range"), sigc::mem_fun(*this, &Editor::new_transport_marker_menu_set_loop)));
966         items.push_back (MenuElem (_("Set Punch Range"), sigc::mem_fun(*this, &Editor::new_transport_marker_menu_set_punch)));
967
968         new_transport_marker_menu->signal_unmap().connect ( sigc::mem_fun(*this, &Editor::new_transport_marker_menu_popdown));
969 }
970
971 void
972 Editor::marker_menu_hide ()
973 {
974         Marker* marker;
975
976         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
977                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
978                 /*NOTREACHED*/
979         }
980
981         Location* l;
982         bool is_start;
983
984         if ((l = find_location_from_marker (marker, is_start)) != 0) {
985                 l->set_hidden (true, this);
986         }
987 }
988
989 void
990 Editor::marker_menu_select_using_range ()
991 {
992         Marker* marker;
993
994         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
995                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
996                 /*NOTREACHED*/
997         }
998
999         Location* l;
1000         bool is_start;
1001
1002         if (((l = find_location_from_marker (marker, is_start)) != 0) && (l->end() > l->start())) {
1003                 set_selection_from_range (*l);
1004         }
1005 }
1006
1007 void
1008 Editor::marker_menu_select_all_selectables_using_range ()
1009 {
1010         Marker* marker;
1011
1012         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
1013                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1014                 /*NOTREACHED*/
1015         }
1016
1017         Location* l;
1018         bool is_start;
1019
1020         if (((l = find_location_from_marker (marker, is_start)) != 0) && (l->end() > l->start())) {
1021                 select_all_within (l->start(), l->end() - 1, 0,  DBL_MAX, track_views, Selection::Set, false);
1022         }
1023
1024 }
1025
1026 void
1027 Editor::marker_menu_separate_regions_using_location ()
1028 {
1029         Marker* marker;
1030
1031         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
1032                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1033                 /*NOTREACHED*/
1034         }
1035
1036         Location* l;
1037         bool is_start;
1038
1039         if (((l = find_location_from_marker (marker, is_start)) != 0) && (l->end() > l->start())) {
1040                 separate_regions_using_location (*l);
1041         }
1042
1043 }
1044
1045 void
1046 Editor::marker_menu_play_from ()
1047 {
1048         Marker* marker;
1049
1050         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
1051                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1052                 /*NOTREACHED*/
1053         }
1054
1055         Location* l;
1056         bool is_start;
1057
1058         if ((l = find_location_from_marker (marker, is_start)) != 0) {
1059
1060                 if (l->is_mark()) {
1061                         _session->request_locate (l->start(), true);
1062                 }
1063                 else {
1064                         //_session->request_bounded_roll (l->start(), l->end());
1065
1066                         if (is_start) {
1067                                 _session->request_locate (l->start(), true);
1068                         } else {
1069                                 _session->request_locate (l->end(), true);
1070                         }
1071                 }
1072         }
1073 }
1074
1075 void
1076 Editor::marker_menu_set_playhead ()
1077 {
1078         Marker* marker;
1079
1080         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
1081                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1082                 /*NOTREACHED*/
1083         }
1084
1085         Location* l;
1086         bool is_start;
1087
1088         if ((l = find_location_from_marker (marker, is_start)) != 0) {
1089
1090                 if (l->is_mark()) {
1091                         _session->request_locate (l->start(), false);
1092                 }
1093                 else {
1094                         if (is_start) {
1095                                 _session->request_locate (l->start(), false);
1096                         } else {
1097                                 _session->request_locate (l->end(), false);
1098                         }
1099                 }
1100         }
1101 }
1102
1103 void
1104 Editor::marker_menu_range_to_next ()
1105 {
1106         Marker* marker;
1107         if (!_session) {
1108                 return;
1109         }
1110
1111         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
1112                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1113                 /*NOTREACHED*/
1114         }
1115
1116         Location* l;
1117         bool is_start;
1118
1119         if ((l = find_location_from_marker (marker, is_start)) == 0) {
1120                 return;
1121         }
1122
1123         framepos_t start;
1124         framepos_t end;
1125         _session->locations()->marks_either_side (marker->position(), start, end);
1126
1127         if (end != max_framepos) {
1128                 string range_name = l->name();
1129                 range_name += "-range";
1130
1131                 Location* newrange = new Location (*_session, marker->position(), end, range_name, Location::IsRangeMarker);
1132                 _session->locations()->add (newrange);
1133         }
1134 }
1135
1136 void
1137 Editor::marker_menu_set_from_playhead ()
1138 {
1139         Marker* marker;
1140
1141         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
1142                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1143                 /*NOTREACHED*/
1144         }
1145
1146         Location* l;
1147         bool is_start;
1148
1149         if ((l = find_location_from_marker (marker, is_start)) != 0) {
1150
1151                 if (l->is_mark()) {
1152                         l->set_start (_session->audible_frame ());
1153                 }
1154                 else {
1155                         if (is_start) {
1156                                 l->set_start (_session->audible_frame ());
1157                         } else {
1158                                 l->set_end (_session->audible_frame ());
1159                         }
1160                 }
1161         }
1162 }
1163
1164 void
1165 Editor::marker_menu_set_from_selection (bool /*force_regions*/)
1166 {
1167         Marker* marker;
1168
1169         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
1170                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1171                 /*NOTREACHED*/
1172         }
1173
1174         Location* l;
1175         bool is_start;
1176
1177         if ((l = find_location_from_marker (marker, is_start)) != 0) {
1178
1179                 if (l->is_mark()) {
1180
1181                         // nothing for now
1182
1183                 } else {
1184                         
1185                         if (!selection->time.empty()) {
1186                                 l->set (selection->time.start(), selection->time.end_frame());
1187                         } else if (!selection->regions.empty()) {
1188                                 l->set (selection->regions.start(), selection->regions.end_frame());
1189                         }
1190                 }
1191         }
1192 }
1193
1194
1195 void
1196 Editor::marker_menu_play_range ()
1197 {
1198         Marker* marker;
1199
1200         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
1201                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1202                 /*NOTREACHED*/
1203         }
1204
1205         Location* l;
1206         bool is_start;
1207
1208         if ((l = find_location_from_marker (marker, is_start)) != 0) {
1209
1210                 if (l->is_mark()) {
1211                         _session->request_locate (l->start(), true);
1212                 }
1213                 else {
1214                         _session->request_bounded_roll (l->start(), l->end());
1215
1216                 }
1217         }
1218 }
1219
1220 void
1221 Editor::marker_menu_loop_range ()
1222 {
1223         Marker* marker;
1224
1225         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
1226                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1227                 /*NOTREACHED*/
1228         }
1229
1230         Location* l;
1231         bool is_start;
1232
1233         if ((l = find_location_from_marker (marker, is_start)) != 0) {
1234                 Location* l2;
1235                 if ((l2 = transport_loop_location()) != 0) {
1236                         l2->set (l->start(), l->end());
1237
1238                         // enable looping, reposition and start rolling
1239                         _session->request_play_loop(true);
1240                         _session->request_locate (l2->start(), true);
1241                 }
1242         }
1243 }
1244
1245 /** Temporal zoom to the range of the marker_menu_item (plus 5% either side) */
1246 void
1247 Editor::marker_menu_zoom_to_range ()
1248 {
1249         Marker* marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"));
1250         assert (marker);
1251
1252         bool is_start;
1253         Location* l = find_location_from_marker (marker, is_start);
1254         if (l == 0) {
1255                 return;
1256         }
1257
1258         framecnt_t const extra = l->length() * 0.05;
1259         framepos_t a = l->start ();
1260         if (a >= extra) {
1261                 a -= extra;
1262         }
1263         
1264         framepos_t b = l->end ();
1265         if (b < (max_framepos - extra)) {
1266                 b += extra;
1267         }
1268
1269         temporal_zoom_by_frame (a, b);
1270 }
1271
1272 void
1273 Editor::dynamic_cast_marker_object (void* p, MeterMarker** m, TempoMarker** t) const
1274 {
1275         Marker* marker = reinterpret_cast<Marker*> (p);
1276         if (!marker) {
1277                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1278                 /*NOTREACHED*/
1279         }
1280
1281         *m = dynamic_cast<MeterMarker*> (marker);
1282         *t = dynamic_cast<TempoMarker*> (marker);
1283 }
1284
1285 void
1286 Editor::marker_menu_edit ()
1287 {
1288         MeterMarker* mm;
1289         TempoMarker* tm;
1290         dynamic_cast_marker_object (marker_menu_item->get_data ("marker"), &mm, &tm);
1291
1292         if (mm) {
1293                 edit_meter_section (&mm->meter());
1294         } else if (tm) {
1295                 edit_tempo_section (&tm->tempo());
1296         }
1297 }
1298
1299 void
1300 Editor::marker_menu_remove ()
1301 {
1302         MeterMarker* mm;
1303         TempoMarker* tm;
1304         dynamic_cast_marker_object (marker_menu_item->get_data ("marker"), &mm, &tm);
1305
1306         if (mm) {
1307                 remove_meter_marker (marker_menu_item);
1308         } else if (tm) {
1309                 remove_tempo_marker (marker_menu_item);
1310         } else {
1311                 remove_marker (*marker_menu_item, (GdkEvent*) 0);
1312         }
1313 }
1314
1315 void
1316 Editor::toggle_marker_menu_lock ()
1317 {
1318         Marker* marker;
1319
1320         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
1321                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1322                 /*NOTREACHED*/
1323         }
1324
1325         Location* loc;
1326         bool ignored;
1327
1328         loc = find_location_from_marker (marker, ignored);
1329
1330         if (!loc) {
1331                 return;
1332         }
1333
1334         if (loc->locked()) {
1335                 loc->unlock ();
1336         } else {
1337                 loc->lock ();
1338         }
1339 }
1340
1341 void
1342 Editor::marker_menu_rename ()
1343 {
1344         Marker* marker;
1345
1346         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
1347                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1348                 /*NOTREACHED*/
1349         }
1350
1351
1352         rename_marker (marker);
1353 }
1354
1355 void
1356 Editor::rename_marker(Marker *marker)
1357 {
1358         Location* loc;
1359         bool is_start;
1360
1361         loc = find_location_from_marker (marker, is_start);
1362
1363         if (!loc)
1364                return;
1365
1366         if (loc == transport_loop_location() || loc == transport_punch_location() || loc->is_session_range())
1367                 return;
1368
1369         ArdourPrompter dialog (true);
1370         string txt;
1371
1372         dialog.set_prompt (_("New Name:"));
1373
1374         if (loc->is_mark()) {
1375                 dialog.set_title (_("Rename Mark"));
1376         } else {
1377                 dialog.set_title (_("Rename Range"));
1378         }
1379
1380         dialog.set_name ("MarkRenameWindow");
1381         dialog.set_size_request (250, -1);
1382         dialog.set_position (Gtk::WIN_POS_MOUSE);
1383
1384         dialog.add_button (_("Rename"), RESPONSE_ACCEPT);
1385         dialog.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1386         dialog.set_initial_text (loc->name());
1387
1388         dialog.show ();
1389
1390         switch (dialog.run ()) {
1391         case RESPONSE_ACCEPT:
1392                 break;
1393         default:
1394                 return;
1395         }
1396
1397         begin_reversible_command ( _("rename marker") );
1398         XMLNode &before = _session->locations()->get_state();
1399
1400         dialog.get_result(txt);
1401         loc->set_name (txt);
1402         _session->set_dirty ();
1403
1404         XMLNode &after = _session->locations()->get_state();
1405         _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1406         commit_reversible_command ();
1407 }
1408
1409 void
1410 Editor::new_transport_marker_menu_popdown ()
1411 {
1412         // hide rects
1413         transport_bar_drag_rect->hide();
1414
1415         _drags->abort ();
1416 }
1417
1418 void
1419 Editor::new_transport_marker_menu_set_loop ()
1420 {
1421         set_loop_range (temp_location->start(), temp_location->end(), _("set loop range"));
1422 }
1423
1424 void
1425 Editor::new_transport_marker_menu_set_punch ()
1426 {
1427         set_punch_range (temp_location->start(), temp_location->end(), _("set punch range"));
1428 }
1429
1430 void
1431 Editor::update_loop_range_view ()
1432 {
1433         if (_session == 0) {
1434                 return;
1435         }
1436
1437         Location* tll;
1438
1439         if (_session->get_play_loop() && ((tll = transport_loop_location()) != 0)) {
1440
1441                 double x1 = sample_to_pixel (tll->start());
1442                 double x2 = sample_to_pixel (tll->end());
1443
1444                 transport_loop_range_rect->set_x0 (x1);
1445                 transport_loop_range_rect->set_x1 (x2);
1446
1447                 transport_loop_range_rect->show();
1448                 
1449         } else {
1450                 transport_loop_range_rect->hide();
1451         }
1452 }
1453
1454 void
1455 Editor::update_punch_range_view ()
1456 {
1457         if (_session == 0) {
1458                 return;
1459         }
1460
1461         Location* tpl;
1462
1463         if ((_session->config.get_punch_in() || _session->config.get_punch_out()) && ((tpl = transport_punch_location()) != 0)) {
1464                 ArdourCanvas::Rect const v = _track_canvas->visible_area ();
1465
1466                 if (_session->config.get_punch_in()) {
1467                         transport_punch_range_rect->set_x0 (sample_to_pixel (tpl->start()));
1468                         transport_punch_range_rect->set_x1 (_session->config.get_punch_out() ? sample_to_pixel (tpl->end()) : sample_to_pixel (JACK_MAX_FRAMES));
1469                 } else {
1470                         transport_punch_range_rect->set_x0 (0);
1471                         transport_punch_range_rect->set_x1 (_session->config.get_punch_out() ? sample_to_pixel (tpl->end()) : v.width ());
1472                 }
1473                 
1474                 transport_punch_range_rect->show();
1475
1476         } else {
1477
1478                 transport_punch_range_rect->hide();
1479         }
1480 }
1481
1482 void
1483 Editor::marker_selection_changed ()
1484 {
1485         if (_session && _session->deletion_in_progress()) {
1486                 return;
1487         }
1488
1489         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1490                 i->second->set_selected (false);
1491         }
1492
1493         for (MarkerSelection::iterator x = selection->markers.begin(); x != selection->markers.end(); ++x) {
1494                 (*x)->set_selected (true);
1495         }
1496 }
1497
1498 struct SortLocationsByPosition {
1499     bool operator() (Location* a, Location* b) {
1500             return a->start() < b->start();
1501     }
1502 };
1503
1504 void
1505 Editor::goto_nth_marker (int n)
1506 {
1507         if (!_session) {
1508                 return;
1509         }
1510         const Locations::LocationList& l (_session->locations()->list());
1511         Locations::LocationList ordered;
1512         ordered = l;
1513
1514         SortLocationsByPosition cmp;
1515         ordered.sort (cmp);
1516
1517         for (Locations::LocationList::iterator i = ordered.begin(); n >= 0 && i != ordered.end(); ++i) {
1518                 if ((*i)->is_mark() && !(*i)->is_hidden() && !(*i)->is_session_range()) {
1519                         if (n == 0) {
1520                                 _session->request_locate ((*i)->start(), _session->transport_rolling());
1521                                 break;
1522                         }
1523                         --n;
1524                 }
1525         }
1526 }
1527
1528 void
1529 Editor::toggle_marker_menu_glue ()
1530 {
1531         Marker* marker;
1532
1533         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
1534                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
1535                 /*NOTREACHED*/
1536         }
1537
1538         Location* loc;
1539         bool ignored;
1540
1541         loc = find_location_from_marker (marker, ignored);
1542
1543         if (!loc) {
1544                 return;
1545         }
1546
1547         if (loc->position_lock_style() == MusicTime) {
1548                 loc->set_position_lock_style (AudioTime);
1549         } else {
1550                 loc->set_position_lock_style (MusicTime);
1551         }
1552
1553 }
1554
1555 void
1556 Editor::toggle_marker_lines ()
1557 {
1558         _show_marker_lines = !_show_marker_lines;
1559
1560         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1561                 i->second->set_show_lines (_show_marker_lines);
1562         }
1563 }
1564
1565 void
1566 Editor::remove_sorted_marker (Marker* m)
1567 {
1568         for (std::map<ArdourCanvas::Group *, std::list<Marker *> >::iterator i = _sorted_marker_lists.begin(); i != _sorted_marker_lists.end(); ++i) {
1569                 i->second.remove (m);
1570         }
1571 }
1572
1573 Marker *
1574 Editor::find_marker_from_location_id (PBD::ID const & id, bool is_start) const
1575 {
1576         for (LocationMarkerMap::const_iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1577                 if (i->first->id() == id) {
1578                         return is_start ? i->second->start : i->second->end;
1579                 }
1580         }
1581
1582         return 0;
1583 }