r191@gandalf: fugalh | 2006-07-24 19:50:10 -0600
[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     $Id$
19 */
20
21 #include <sigc++/retype.h>
22 #include <cstdlib>
23 #include <cmath>
24
25 #include <libgnomecanvas/libgnomecanvas.h>
26 #include <gtkmm2ext/gtk_ui.h>
27
28 #include <ardour/location.h>
29
30 #include "editor.h"
31 #include "marker.h"
32 #include "selection.h"
33 #include "editing.h"
34 #include "gui_thread.h"
35 #include "simplerect.h"
36 #include "actions.h"
37 #include "prompter.h"
38
39 #include "i18n.h"
40
41 using namespace std;
42 using namespace sigc;
43 using namespace ARDOUR;
44 using namespace PBD;
45 using namespace Gtk;
46
47 void
48 Editor::clear_marker_display ()
49 {
50         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
51                 delete i->second;
52         }
53
54         location_markers.clear ();
55 }
56
57 void
58 Editor::add_new_location (Location *location)
59 {
60         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::add_new_location), location));
61
62         LocationMarkers *lam = new LocationMarkers;
63         uint32_t color;
64
65         if (location->is_cd_marker()) {
66                 color = location_cd_marker_color;
67         } else if (location->is_mark()) {
68                 color = location_marker_color;
69         } else if (location->is_auto_loop()) {
70                 color = location_loop_color;
71         } else if (location->is_auto_punch()) {
72                 color = location_punch_color;
73         } else {
74                 color = location_range_color;
75         }
76
77         if (location->is_mark()) {
78                 lam->start = new Marker (*this, *marker_group, color, location->name(), Marker::Mark, location->start());
79                 lam->end   = 0;
80
81         } else if (location->is_auto_loop()) {
82                 // transport marker
83                 lam->start = new Marker (*this, *transport_marker_group, color, 
84                                          location->name(), Marker::LoopStart, location->start());
85                 lam->end   = new Marker (*this, *transport_marker_group, color, 
86                                          location->name(), Marker::LoopEnd, location->end());
87                 
88         } else if (location->is_auto_punch()) {
89                 // transport marker
90                 lam->start = new Marker (*this, *transport_marker_group, color, 
91                                          location->name(), Marker::PunchIn, location->start());
92                 lam->end   = new Marker (*this, *transport_marker_group, color, 
93                                          location->name(), Marker::PunchOut, location->end());
94                 
95         } else {
96
97                 // range marker
98                 lam->start = new Marker (*this, *range_marker_group, color, 
99                                          location->name(), Marker::Start, location->start());
100                 lam->end   = new Marker (*this, *range_marker_group, color, 
101                                          location->name(), Marker::End, location->end());
102         }
103
104         if (location->is_hidden ()) {
105                 lam->hide();
106         } else {
107                 lam->show ();
108         }
109
110         location->start_changed.connect (mem_fun(*this, &Editor::location_changed));
111         location->end_changed.connect (mem_fun(*this, &Editor::location_changed));
112         location->changed.connect (mem_fun(*this, &Editor::location_changed));
113         location->name_changed.connect (mem_fun(*this, &Editor::location_changed));
114         location->FlagsChanged.connect (mem_fun(*this, &Editor::location_flags_changed));
115
116         pair<Location*,LocationMarkers*> newpair;
117
118         newpair.first = location;
119         newpair.second = lam;
120
121         location_markers.insert (newpair);
122 }
123
124 void
125 Editor::location_changed (Location *location)
126 {
127         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::location_changed), location));
128
129         LocationMarkers *lam = find_location_markers (location);
130
131         if (lam == 0) {
132                 /* a location that isn't "marked" with markers */
133                 return;
134         }
135         
136         lam->set_name (location->name());
137         lam->set_position (location->start(), location->end());
138
139         if (location->is_auto_loop()) {
140                 update_loop_range_view ();
141         } else if (location->is_auto_punch()) {
142                 update_punch_range_view ();
143         }
144 }
145
146 void
147 Editor::location_flags_changed (Location *location, void *src)
148 {
149         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::location_flags_changed), location, src));
150         
151         LocationMarkers *lam = find_location_markers (location);
152         
153         if (lam == 0) {
154                 /* a location that isn't "marked" with markers */
155                 return;
156         }
157
158         if (location->is_cd_marker()) {
159                 lam->set_color_rgba (location_cd_marker_color);
160         } else if (location->is_mark()) {
161                 lam->set_color_rgba (location_marker_color);
162         } else if (location->is_auto_punch()) {
163                 lam->set_color_rgba (location_punch_color);
164         } else if (location->is_auto_loop()) {
165                 lam->set_color_rgba (location_loop_color);
166         } else {
167                 lam->set_color_rgba (location_range_color);
168         }
169         
170         if (location->is_hidden()) {
171                 lam->hide();
172         } else {
173                 lam->show ();
174         }
175 }
176
177 Editor::LocationMarkers::~LocationMarkers ()
178 {
179         if (start) {
180                 delete start;
181         }
182
183         if (end) {
184                 delete end;
185         }
186 }
187
188 Editor::LocationMarkers *
189 Editor::find_location_markers (Location *location)
190 {
191         LocationMarkerMap::iterator i;
192
193         for (i = location_markers.begin(); i != location_markers.end(); ++i) {
194                 if ((*i).first == location) {
195                         return (*i).second;
196                 }
197         }
198
199         return 0;
200 }
201
202 Location *
203 Editor::find_location_from_marker (Marker *marker, bool& is_start)
204 {
205         LocationMarkerMap::iterator i;
206
207         for (i = location_markers.begin(); i != location_markers.end(); ++i) {
208                 LocationMarkers *lm = (*i).second;
209                 if (lm->start == marker) {
210                         is_start = true;
211                         return (*i).first;
212                 } else if (lm->end == marker) {
213                         is_start = false;
214                         return (*i).first;
215                 }
216         }
217
218         return 0;
219 }
220
221 void
222 Editor::refresh_location_display_internal (Locations::LocationList& locations)
223 {
224         clear_marker_display ();
225         
226         for (Locations::LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
227                 add_new_location (*i);
228         }
229 }
230
231 void
232 Editor::refresh_location_display ()
233 {
234         ENSURE_GUI_THREAD(mem_fun(*this, &Editor::refresh_location_display));
235         
236         if (session) {
237                 session->locations()->apply (*this, &Editor::refresh_location_display_internal);
238         }
239 }
240
241 void
242 Editor::refresh_location_display_s (Change ignored)
243 {
244         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::refresh_location_display_s), ignored));
245
246         if (session) {
247                 session->locations()->apply (*this, &Editor::refresh_location_display_internal);
248         }
249 }
250
251 void
252 Editor::LocationMarkers::hide() 
253 {
254         start->hide ();
255         if (end) { end->hide(); }
256 }
257
258 void
259 Editor::LocationMarkers::show() 
260 {
261         start->show ();
262         if (end) { end->show(); }
263 }
264
265 void
266 Editor::LocationMarkers::set_name (const string& str) 
267 {
268         start->set_name (str);
269         if (end) { end->set_name (str); }
270 }
271
272 void
273 Editor::LocationMarkers::set_position (jack_nframes_t startf, 
274                                        jack_nframes_t endf) 
275 {
276         start->set_position (startf);
277         if (end) { end->set_position (endf); }
278 }
279
280 void
281 Editor::LocationMarkers::set_color_rgba (uint32_t rgba) 
282 {
283         start->set_color_rgba (rgba);
284         if (end) { end->set_color_rgba (rgba); }
285 }
286
287 void
288 Editor::mouse_add_new_marker (jack_nframes_t where)
289 {
290         if (session) {
291                 Location *location = new Location (where, where, "mark", Location::IsMark);
292                 session->begin_reversible_command (_("add marker"));
293                 XMLNode &before, &after;
294                 before = session->locations()->get_state();
295                 session->locations()->add (location, true);
296                 after = session->locations()->get_state();
297                 session->add_command (MementoCommand<Locations>(*(session->locations()), before, after));
298                 session->commit_reversible_command ();
299         }
300 }
301
302 void
303 Editor::remove_marker (ArdourCanvas::Item& item, GdkEvent* event)
304 {
305         Marker* marker;
306         bool is_start;
307
308         if ((marker = static_cast<Marker*> (item.get_data ("marker"))) == 0) {
309                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
310                 /*NOTREACHED*/
311         }
312
313         Location* loc = find_location_from_marker (marker, is_start);
314
315         if (session && loc) {
316                 if (loc->is_end()) {
317                         /* you can't hide or delete this marker */
318                         return;
319                 }
320                 if (loc->is_auto_loop() || loc->is_auto_punch()) {
321                         // just hide them
322                         loc->set_hidden (true, this);
323                 }
324                 else {
325                         Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::really_remove_marker), loc));
326                 }
327         }
328 }
329
330 gint
331 Editor::really_remove_marker (Location* loc)
332 {
333         session->begin_reversible_command (_("remove marker"));
334         XMLNode &before, &after;
335         before = session->locations()->get_state();
336         session->locations()->remove (loc);
337         after = session->locations()->get_state();
338         session->add_command (MementoCommand<Locations>(*(session->locations()), before, after));
339         session->commit_reversible_command ();
340         return FALSE;
341 }
342
343 void
344 Editor::location_gone (Location *location)
345 {
346         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::location_gone), location));
347         
348         LocationMarkerMap::iterator i;
349
350         if (location == transport_loop_location()) {
351                 update_loop_range_view (true);
352         }
353
354         if (location == transport_punch_location()) {
355                 update_punch_range_view (true);
356         }
357         
358         for (i = location_markers.begin(); i != location_markers.end(); ++i) {
359                 if ((*i).first == location) {
360                         delete (*i).second;
361                         location_markers.erase (i);
362                         break;
363                 }
364         }
365 }
366
367 void
368 Editor::tm_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
369 {
370         if (tm_marker_menu == 0) {
371                 build_tm_marker_menu ();
372         }
373
374         marker_menu_item = item;
375         tm_marker_menu->popup (1, ev->time);
376
377 }
378
379 void
380 Editor::marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
381 {
382         Marker * marker;
383         if ((marker = reinterpret_cast<Marker *> (item->get_data("marker"))) == 0) {
384                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
385                 /*NOTREACHED*/
386         }
387         
388         bool is_start;
389         Location * loc = find_location_from_marker (marker, is_start);
390         if (loc == transport_loop_location() || loc == transport_punch_location()) {
391                 if (transport_marker_menu == 0) {
392                         build_transport_marker_menu ();
393                 }
394                 marker_menu_item = item;
395                 transport_marker_menu->popup (1, ev->time);
396         } else {
397
398                 if (loc->is_mark()) {
399                        if (marker_menu == 0) {
400                               build_marker_menu ();
401                        }
402
403
404                 // GTK2FIX use action group sensitivity
405 #ifdef GTK2FIX
406                 if (children.size() >= 3) {
407                         MenuItem * loopitem = &children[2];
408                         if (loopitem) {
409                                 if (loc->is_mark()) {
410                                         loopitem->set_sensitive(false);
411                                 }
412                                 else {
413                                         loopitem->set_sensitive(true);
414                                 }
415                         }
416                 }
417 #endif          
418                 marker_menu_item = item;
419                 marker_menu->popup (1, ev->time);
420                 }
421
422                 if (loc->is_range_marker()) {
423                        if (range_marker_menu == 0){
424                               build_range_marker_menu ();
425                        }
426                        marker_menu_item = item;
427                        range_marker_menu->popup (1, ev->time);
428                 }
429         }
430 }
431
432 void
433 Editor::new_transport_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
434 {
435         if (new_transport_marker_menu == 0) {
436                 build_new_transport_marker_menu ();
437         }
438
439         new_transport_marker_menu->popup (1, ev->time);
440
441 }
442
443 void
444 Editor::transport_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
445 {
446         if (transport_marker_menu == 0) {
447                 build_transport_marker_menu ();
448         }
449
450         transport_marker_menu->popup (1, ev->time);
451 }
452
453 void
454 Editor::build_marker_menu ()
455 {
456         using namespace Menu_Helpers;
457
458         marker_menu = new Menu;
459         MenuList& items = marker_menu->items();
460         marker_menu->set_name ("ArdourContextMenu");
461
462         items.push_back (MenuElem (_("Locate to Mark"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
463         items.push_back (MenuElem (_("Play from Mark"), mem_fun(*this, &Editor::marker_menu_play_from)));
464         items.push_back (MenuElem (_("Set Mark from Playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
465
466         items.push_back (SeparatorElem());
467
468         items.push_back (MenuElem (_("Rename Mark"), mem_fun(*this, &Editor::marker_menu_rename)));
469         items.push_back (MenuElem (_("Hide Mark"), mem_fun(*this, &Editor::marker_menu_hide)));
470         items.push_back (MenuElem (_("Remove Mark"), mem_fun(*this, &Editor::marker_menu_remove)));
471
472 }
473
474 void
475 Editor::build_range_marker_menu ()
476 {
477         using namespace Menu_Helpers;
478
479         range_marker_menu = new Menu;
480         MenuList& items = range_marker_menu->items();
481         range_marker_menu->set_name ("ArdourContextMenu");
482
483         items.push_back (MenuElem (_("Locate to Range Mark"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
484         items.push_back (MenuElem (_("Play from Range Mark"), mem_fun(*this, &Editor::marker_menu_play_from)));
485         items.push_back (MenuElem (_("Loop Range"), mem_fun(*this, &Editor::marker_menu_loop_range)));
486         items.push_back (MenuElem (_("Set Range Mark from Playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
487         items.push_back (MenuElem (_("Set Range from Range Selection"), mem_fun(*this, &Editor::marker_menu_set_from_selection)));
488
489         items.push_back (SeparatorElem());
490
491         items.push_back (MenuElem (_("Rename Range"), mem_fun(*this, &Editor::marker_menu_rename)));
492         items.push_back (MenuElem (_("Hide Range"), mem_fun(*this, &Editor::marker_menu_hide)));
493         items.push_back (MenuElem (_("Remove Range"), mem_fun(*this, &Editor::marker_menu_remove)));
494
495         items.push_back (SeparatorElem());
496
497         items.push_back (MenuElem (_("Separate Regions in Range"), mem_fun(*this, &Editor::marker_menu_separate_regions_using_location)));
498         items.push_back (MenuElem (_("Select All in Range"), mem_fun(*this, &Editor::marker_menu_select_all_selectables_using_range)));
499
500 }
501
502 void
503 Editor::build_tm_marker_menu ()
504 {
505         using namespace Menu_Helpers;
506
507         tm_marker_menu = new Menu;
508         MenuList& items = tm_marker_menu->items();
509         tm_marker_menu->set_name ("ArdourContextMenu");
510
511         items.push_back (MenuElem (_("Edit"), mem_fun(*this, &Editor::marker_menu_edit)));
512         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::marker_menu_remove)));
513 }
514
515 void
516 Editor::build_new_transport_marker_menu ()
517 {
518         using namespace Menu_Helpers;
519
520         new_transport_marker_menu = new Menu;
521         MenuList& items = new_transport_marker_menu->items();
522         new_transport_marker_menu->set_name ("ArdourContextMenu");
523
524         items.push_back (MenuElem (_("Set Loop Range"), mem_fun(*this, &Editor::new_transport_marker_menu_set_loop)));
525         items.push_back (MenuElem (_("Set Punch Range"), mem_fun(*this, &Editor::new_transport_marker_menu_set_punch)));
526
527         new_transport_marker_menu->signal_unmap_event().connect ( mem_fun(*this, &Editor::new_transport_marker_menu_popdown)); 
528 }
529
530 void
531 Editor::build_transport_marker_menu ()
532 {
533         using namespace Menu_Helpers;
534
535         transport_marker_menu = new Menu;
536         MenuList& items = transport_marker_menu->items();
537         transport_marker_menu->set_name ("ArdourContextMenu");
538
539         items.push_back (MenuElem (_("Locate to Range Mark"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
540         items.push_back (MenuElem (_("Play from Range Mark"), mem_fun(*this, &Editor::marker_menu_play_from)));
541         items.push_back (MenuElem (_("Set Range Mark from Playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
542         items.push_back (MenuElem (_("Set Range from Range Selection"), mem_fun(*this, &Editor::marker_menu_set_from_selection)));
543         items.push_back (SeparatorElem());
544         items.push_back (MenuElem (_("Hide Range"), mem_fun(*this, &Editor::marker_menu_hide)));
545         items.push_back (SeparatorElem());
546         items.push_back (MenuElem (_("Separate Regions in Range"), mem_fun(*this, &Editor::marker_menu_separate_regions_using_location)));
547         items.push_back (MenuElem (_("Select All in Range"), mem_fun(*this, &Editor::marker_menu_select_all_selectables_using_range)));
548 }
549
550 void
551 Editor::marker_menu_hide ()
552 {
553         Marker* marker;
554
555         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
556                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
557                 /*NOTREACHED*/
558         }
559
560         Location* l;
561         bool is_start;
562         
563         if ((l = find_location_from_marker (marker, is_start)) != 0) {
564                 l->set_hidden (true, this);
565         }
566 }
567
568 void
569 Editor::marker_menu_select_all_selectables_using_range ()
570 {
571         Marker* marker;
572
573         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
574                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
575                 /*NOTREACHED*/
576         }
577
578         Location* l;
579         bool is_start;
580
581         if (((l = find_location_from_marker (marker, is_start)) != 0) && (l->end() > l->start())) {
582                 select_all_within (l->start(), l->end() - 1, 0,  DBL_MAX, Selection::Set);
583         }
584           
585 }
586
587 void
588 Editor::marker_menu_separate_regions_using_location ()
589 {
590         Marker* marker;
591
592         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
593                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
594                 /*NOTREACHED*/
595         }
596
597         Location* l;
598         bool is_start;
599
600         if (((l = find_location_from_marker (marker, is_start)) != 0) && (l->end() > l->start())) {
601                 separate_regions_using_location (*l);
602         }
603           
604 }
605
606 void
607 Editor::marker_menu_play_from ()
608 {
609         Marker* marker;
610
611         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
612                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
613                 /*NOTREACHED*/
614         }
615
616         Location* l;
617         bool is_start;
618         
619         if ((l = find_location_from_marker (marker, is_start)) != 0) {
620
621                 if (l->is_mark()) {
622                         session->request_locate (l->start(), true);
623                 }
624                 else {
625                         //session->request_bounded_roll (l->start(), l->end());
626                         
627                         if (is_start) {
628                                 session->request_locate (l->start(), true);
629                         } else {
630                                 session->request_locate (l->end(), true);
631                         }
632                 }
633         }
634 }
635
636 void
637 Editor::marker_menu_set_playhead ()
638 {
639         Marker* marker;
640
641         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
642                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
643                 /*NOTREACHED*/
644         }
645
646         Location* l;
647         bool is_start;
648         
649         if ((l = find_location_from_marker (marker, is_start)) != 0) {
650
651                 if (l->is_mark()) {
652                         session->request_locate (l->start(), false);
653                 }
654                 else {
655                         if (is_start) {
656                                 session->request_locate (l->start(), false);
657                         } else {
658                                 session->request_locate (l->end(), false);
659                         }
660                 }
661         }
662 }
663
664 void
665 Editor::marker_menu_set_from_playhead ()
666 {
667         Marker* marker;
668
669         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
670                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
671                 /*NOTREACHED*/
672         }
673
674         Location* l;
675         bool is_start;
676         
677         if ((l = find_location_from_marker (marker, is_start)) != 0) {
678
679                 if (l->is_mark()) {
680                         l->set_start (session->transport_frame ());
681                 }
682                 else {
683                         if (is_start) {
684                                 l->set_start (session->transport_frame ());
685                         } else {
686                                 l->set_end (session->transport_frame ());
687                         }
688                 }
689         }
690 }
691
692 void
693 Editor::marker_menu_set_from_selection ()
694 {
695         Marker* marker;
696
697         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
698                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
699                 /*NOTREACHED*/
700         }
701
702         Location* l;
703         bool is_start;
704         
705         if ((l = find_location_from_marker (marker, is_start)) != 0) {
706
707                 if (l->is_mark()) {
708                         // nothing for now
709                 }
710                 else {
711
712                         /* if range selection use first to last */
713
714                         if (mouse_mode == Editing::MouseRange) {
715                                 if (!selection->time.empty()) {
716                                         l->set_start (selection->time.start());
717                                         l->set_end (selection->time.end_frame());
718                                 }
719                         }
720                         else {
721                                 if (!selection->audio_regions.empty()) {
722                                         l->set_start (selection->audio_regions.start());
723                                         l->set_end (selection->audio_regions.end_frame());
724                                 }
725                         }
726                 }
727         }
728 }
729
730 void
731 Editor::marker_menu_loop_range ()
732 {
733         Marker* marker;
734
735         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
736                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
737                 /*NOTREACHED*/
738         }
739
740         Location* l;
741         bool is_start;
742         
743         if ((l = find_location_from_marker (marker, is_start)) != 0) {
744                 Location* l2;
745                 if ((l2 = transport_loop_location()) != 0) {
746                         l2->set (l->start(), l->end());
747                         
748                         // enable looping, reposition and start rolling
749                         session->request_auto_loop(true);
750                         session->request_locate (l2->start(), true);
751                 }
752         }
753 }
754
755 void
756 Editor::marker_menu_edit ()
757 {
758         MeterMarker* mm;
759         TempoMarker* tm;
760         Marker* marker;
761
762         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
763                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
764                 /*NOTREACHED*/
765         }
766
767         if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
768                 edit_meter_section (&mm->meter());
769         } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
770                 edit_tempo_section (&tm->tempo());
771         } else {
772                 fatal << X_("programming erorr: unhandled marker type in Editor::marker_menu_edit")
773                       << endmsg;
774                 /*NOTREACHED*/
775         }
776 }
777
778 void
779 Editor::marker_menu_remove ()
780 {
781         MeterMarker* mm;
782         TempoMarker* tm;
783         Marker* marker;
784
785         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
786                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
787                 /*NOTREACHED*/
788         }
789
790         if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
791                 remove_meter_marker (marker_menu_item);
792         } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
793                 remove_tempo_marker (marker_menu_item);
794         } else {
795                 remove_marker (*marker_menu_item, (GdkEvent*) 0);
796         }
797 }
798
799 void
800 Editor::marker_menu_rename ()
801 {
802         Marker* marker;
803
804         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
805                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
806                 /*NOTREACHED*/
807         }
808
809         Location* loc;
810         bool is_start;
811
812         loc = find_location_from_marker (marker, is_start);
813
814         if (!loc) return;
815         
816         ArdourPrompter dialog (true);
817         string txt;
818
819         dialog.set_prompt (_("New Name:"));
820         
821         if (loc->is_mark()) {
822                 dialog.set_title (_("ardour: rename mark"));
823         } else {
824                 dialog.set_title (_("ardour: rename range"));
825         }
826
827         dialog.set_name ("MarkRenameWindow");
828         dialog.set_size_request (250, -1);
829         dialog.set_position (Gtk::WIN_POS_MOUSE);
830
831         dialog.add_button (_("Rename"), RESPONSE_ACCEPT);
832         dialog.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
833         dialog.set_initial_text (loc->name());
834
835         dialog.show ();
836
837         switch (dialog.run ()) {
838         case RESPONSE_ACCEPT:
839                 break;
840         default:
841                 return;
842         }
843
844         begin_reversible_command ( _("rename marker") );
845         XMLNode &before = session->locations()->get_state();
846
847         dialog.get_result(txt);
848         loc->set_name (txt);
849         
850         XMLNode &after = session->locations()->get_state();
851         session->add_command (MementoCommand<Locations>(*(session->locations()), before, after));
852         commit_reversible_command ();
853 }
854
855 gint
856 Editor::new_transport_marker_menu_popdown (GdkEventAny *ev)
857 {
858         // hide rects
859         transport_bar_drag_rect->hide();
860         range_marker_drag_rect->hide();
861
862         return FALSE;
863 }
864
865 void
866 Editor::new_transport_marker_menu_set_loop ()
867 {
868         if (!session) return;
869         
870         begin_reversible_command (_("set loop range"));
871         
872         Location* tll;
873
874         if ((tll = transport_loop_location()) == 0) {
875                 Location* loc = new Location (temp_location->start(), temp_location->end(), _("Loop"),  Location::IsAutoLoop);
876                 XMLNode &before = session->locations()->get_state();
877                 session->locations()->add (loc, true);
878                 session->set_auto_loop_location (loc);
879                 XMLNode &after = session->locations()->get_state();
880                 session->add_command (MementoCommand<Locations>(*(session->locations()), before, after));
881         }
882         else {
883                 session->add_undo (retype_return<void>(bind (mem_fun (*tll, &Location::set), tll->start(), tll->end())));
884                 session->add_redo (retype_return<void>(bind (mem_fun (*tll, &Location::set), temp_location->start(), temp_location->end())));
885                 tll->set_hidden (false, this);
886                 tll->set (temp_location->start(), temp_location->end());
887         }
888         
889         commit_reversible_command ();
890 }
891
892 void
893 Editor::new_transport_marker_menu_set_punch ()
894 {
895         if (!session) return;
896         
897         begin_reversible_command (_("set punch range"));
898         
899         Location* tpl;
900
901         if ((tpl = transport_punch_location()) == 0) {
902                 tpl = new Location (temp_location->start(), temp_location->end(), _("Punch"), Location::IsAutoPunch);
903                 XMLNode &before = session->locations()->get_state();
904                 session->locations()->add (tpl, true);
905                 session->set_auto_punch_location (tpl);
906                 XMLNode &after = session->locations()->get_state();
907                 session->add_command (MementoCommand<Locations>(*(session->locations()), before, after));
908         } else {
909                 session->add_undo (retype_return<void>(bind (mem_fun (*tpl, &Location::set), tpl->start(), tpl->end())));
910                 session->add_redo (retype_return<void>(bind (mem_fun (*tpl, &Location::set), temp_location->start(), temp_location->end())));
911                 tpl->set_hidden(false, this);
912                 tpl->set(temp_location->start(), temp_location->end());
913         }
914         
915         commit_reversible_command ();
916 }
917
918 void
919 Editor::update_loop_range_view (bool visibility)
920 {
921         if (session == 0) {
922                 return;
923         }
924
925         Location* tll;
926
927         if (session->get_auto_loop() && ((tll = transport_loop_location()) != 0)) {
928
929                 double x1 = frame_to_pixel (tll->start());
930                 double x2 = frame_to_pixel (tll->end());
931                 
932                 transport_loop_range_rect->property_x1() = x1;
933                 transport_loop_range_rect->property_x2() = x2;
934                 
935                 if (visibility) {
936                         transport_loop_range_rect->show();
937                 }
938         }
939         else if (visibility) {
940                 transport_loop_range_rect->hide();
941         }
942 }
943
944 void
945 Editor::update_punch_range_view (bool visibility)
946 {
947         if (session == 0) {
948                 return;
949         }
950
951         Location* tpl;
952
953         if ((session->get_punch_in() || session->get_punch_out()) && ((tpl = transport_punch_location()) != 0)) {
954
955                 double x1 = frame_to_pixel (tpl->start());
956                 double x2 = frame_to_pixel (tpl->end());
957                 
958                 transport_punch_range_rect->property_x1() = x1;
959                 transport_punch_range_rect->property_x2() = x2;
960                 
961                 if (visibility) {
962                         transport_punch_range_rect->show();
963                 }
964         }
965         else if (visibility) {
966                 transport_punch_range_rect->hide();
967         }
968
969 //      if (session->get_punch_in()) {
970 //              double x = frame_to_pixel (transport_punch_location->start());
971 //              gnome_canvas_item_set (transport_punchin_line, "x1", x, "x2", x, NULL);
972                 
973 //              if (visibility) {
974 //                      gnome_canvas_item_show (transport_punchin_line);
975 //              }
976 //      }
977 //      else if (visibility) {
978 //              gnome_canvas_item_hide (transport_punchin_line);
979 //      }
980         
981 //      if (session->get_punch_out()) {
982 //              double x = frame_to_pixel (transport_punch_location->end());
983                 
984 //              gnome_canvas_item_set (transport_punchout_line, "x1", x, "x2", x, NULL);
985                 
986 //              if (visibility) {
987 //                      gnome_canvas_item_show (transport_punchout_line);
988 //              }
989 //      }
990 //      else if (visibility) {
991 //              gnome_canvas_item_hide (transport_punchout_line);
992 //      }
993 }