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