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