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