3245b79c59c8652f2579821a30cb62798099dc6f
[ardour.git] / gtk2_ardour / editor_markers.cc
1 /*
2     Copyright (C) 2000 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <sigc++/retype.h>
21 #include <cstdlib>
22 #include <cmath>
23
24 #include <libgnomecanvas/libgnomecanvas.h>
25 #include <gtkmm2ext/gtk_ui.h>
26
27 #include <ardour/location.h>
28 #include <pbd/memento_command.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 (nframes_t startf, 
274                                        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 (nframes_t where)
289 {
290         string markername;
291         if (session) {
292                 session->locations()->next_available_name(markername,"mark");
293                 Location *location = new Location (where, where, markername, Location::IsMark);
294                 session->begin_reversible_command (_("add marker"));
295                 XMLNode &before = session->locations()->get_state();
296                 session->locations()->add (location, true);
297                 XMLNode &after = session->locations()->get_state();
298                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
299                 session->commit_reversible_command ();
300         }
301 }
302
303 void
304 Editor::remove_marker (ArdourCanvas::Item& item, GdkEvent* event)
305 {
306         Marker* marker;
307         bool is_start;
308
309         if ((marker = static_cast<Marker*> (item.get_data ("marker"))) == 0) {
310                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
311                 /*NOTREACHED*/
312         }
313
314         Location* loc = find_location_from_marker (marker, is_start);
315
316         if (session && loc) {
317                 Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::really_remove_marker), loc));
318         }
319 }
320
321 gint
322 Editor::really_remove_marker (Location* loc)
323 {
324         session->begin_reversible_command (_("remove marker"));
325         XMLNode &before = session->locations()->get_state();
326         session->locations()->remove (loc);
327         XMLNode &after = session->locations()->get_state();
328         session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
329         session->commit_reversible_command ();
330         return FALSE;
331 }
332
333 void
334 Editor::location_gone (Location *location)
335 {
336         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::location_gone), location));
337         
338         LocationMarkerMap::iterator i;
339
340         if (location == transport_loop_location()) {
341                 update_loop_range_view (true);
342         }
343
344         if (location == transport_punch_location()) {
345                 update_punch_range_view (true);
346         }
347         
348         for (i = location_markers.begin(); i != location_markers.end(); ++i) {
349                 if ((*i).first == location) {
350                         delete (*i).second;
351                         location_markers.erase (i);
352                         break;
353                 }
354         }
355 }
356
357 void
358 Editor::tm_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
359 {
360         if (tm_marker_menu == 0) {
361                 build_tm_marker_menu ();
362         }
363
364         marker_menu_item = item;
365         tm_marker_menu->popup (1, ev->time);
366
367 }
368
369 void
370 Editor::marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
371 {
372         Marker * marker;
373         if ((marker = reinterpret_cast<Marker *> (item->get_data("marker"))) == 0) {
374                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
375                 /*NOTREACHED*/
376         }
377         
378         bool is_start;
379         Location * loc = find_location_from_marker (marker, is_start);
380         if (loc == transport_loop_location() || loc == transport_punch_location()) {
381                 if (transport_marker_menu == 0) {
382                         build_range_marker_menu (true);
383                 }
384                 marker_menu_item = item;
385                 transport_marker_menu->popup (1, ev->time);
386         } else {
387
388                 if (loc->is_mark()) {
389                         bool start_or_end = loc->is_start() || loc->is_end();
390                         Menu *markerMenu;
391                         if (start_or_end) {
392                                 if (start_end_marker_menu == 0)
393                                         build_marker_menu (true);
394                                 markerMenu = start_end_marker_menu;
395                         } else {
396                                 if (marker_menu == 0)
397                                         build_marker_menu (false);
398                                 markerMenu = marker_menu;
399                         }
400
401
402                 // GTK2FIX use action group sensitivity
403 #ifdef GTK2FIX
404                 if (children.size() >= 3) {
405                         MenuItem * loopitem = &children[2];
406                         if (loopitem) {
407                                 if (loc->is_mark()) {
408                                         loopitem->set_sensitive(false);
409                                 }
410                                 else {
411                                         loopitem->set_sensitive(true);
412                                 }
413                         }
414                 }
415 #endif          
416                 marker_menu_item = item;
417                 markerMenu->popup (1, ev->time);
418                 }
419
420                 if (loc->is_range_marker()) {
421                        if (range_marker_menu == 0){
422                               build_range_marker_menu (false);
423                        }
424                        marker_menu_item = item;
425                        range_marker_menu->popup (1, ev->time);
426                 }
427         }
428 }
429
430 void
431 Editor::new_transport_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
432 {
433         if (new_transport_marker_menu == 0) {
434                 build_new_transport_marker_menu ();
435         }
436
437         new_transport_marker_menu->popup (1, ev->time);
438
439 }
440
441 void
442 Editor::transport_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
443 {
444         if (transport_marker_menu == 0) {
445                 build_range_marker_menu (true);
446         }
447
448         transport_marker_menu->popup (1, ev->time);
449 }
450
451 void
452 Editor::build_marker_menu (bool start_or_end)
453 {
454         using namespace Menu_Helpers;
455
456         Menu *markerMenu = new Menu;
457         if (start_or_end) {
458                 start_end_marker_menu = markerMenu;
459         } else {
460                 marker_menu = markerMenu;
461         }
462         MenuList& items = markerMenu->items();
463         markerMenu->set_name ("ArdourContextMenu");
464
465         items.push_back (MenuElem (_("Locate to Mark"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
466         items.push_back (MenuElem (_("Play from Mark"), mem_fun(*this, &Editor::marker_menu_play_from)));
467         items.push_back (MenuElem (_("Set Mark from Playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
468
469         items.push_back (SeparatorElem());
470
471         items.push_back (MenuElem (_("Hide Mark"), mem_fun(*this, &Editor::marker_menu_hide)));
472         if (start_or_end) return;
473         items.push_back (MenuElem (_("Rename Mark"), mem_fun(*this, &Editor::marker_menu_rename)));
474         items.push_back (MenuElem (_("Remove Mark"), mem_fun(*this, &Editor::marker_menu_remove)));
475
476 }
477
478 void
479 Editor::build_range_marker_menu (bool loop_or_punch)
480 {
481         using namespace Menu_Helpers;
482
483         Menu *markerMenu = new Menu;
484         if (loop_or_punch) {
485                 transport_marker_menu = markerMenu;
486         } else {
487                 range_marker_menu = markerMenu;
488         }
489         MenuList& items = markerMenu->items();
490         markerMenu->set_name ("ArdourContextMenu");
491
492         items.push_back (MenuElem (_("Locate to Range Mark"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
493         items.push_back (MenuElem (_("Play from Range Mark"), mem_fun(*this, &Editor::marker_menu_play_from)));
494         if (! loop_or_punch) {
495                 items.push_back (MenuElem (_("Play Range"), mem_fun(*this, &Editor::marker_menu_play_range)));
496                 items.push_back (MenuElem (_("Loop Range"), mem_fun(*this, &Editor::marker_menu_loop_range)));
497         }
498         items.push_back (MenuElem (_("Set Range Mark from Playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
499         items.push_back (MenuElem (_("Set Range from Range Selection"), mem_fun(*this, &Editor::marker_menu_set_from_selection)));
500
501         items.push_back (SeparatorElem());
502
503         items.push_back (MenuElem (_("Hide Range"), mem_fun(*this, &Editor::marker_menu_hide)));
504         if (! loop_or_punch) {
505                 items.push_back (MenuElem (_("Rename Range"), mem_fun(*this, &Editor::marker_menu_rename)));
506                 items.push_back (MenuElem (_("Remove Range"), mem_fun(*this, &Editor::marker_menu_remove)));
507         }
508
509         items.push_back (SeparatorElem());
510
511         items.push_back (MenuElem (_("Separate Regions in Range"), mem_fun(*this, &Editor::marker_menu_separate_regions_using_location)));
512         items.push_back (MenuElem (_("Select All in Range"), mem_fun(*this, &Editor::marker_menu_select_all_selectables_using_range)));
513
514 }
515
516 void
517 Editor::build_tm_marker_menu ()
518 {
519         using namespace Menu_Helpers;
520
521         tm_marker_menu = new Menu;
522         MenuList& items = tm_marker_menu->items();
523         tm_marker_menu->set_name ("ArdourContextMenu");
524
525         items.push_back (MenuElem (_("Edit"), mem_fun(*this, &Editor::marker_menu_edit)));
526         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::marker_menu_remove)));
527 }
528
529 void
530 Editor::build_new_transport_marker_menu ()
531 {
532         using namespace Menu_Helpers;
533
534         new_transport_marker_menu = new Menu;
535         MenuList& items = new_transport_marker_menu->items();
536         new_transport_marker_menu->set_name ("ArdourContextMenu");
537
538         items.push_back (MenuElem (_("Set Loop Range"), mem_fun(*this, &Editor::new_transport_marker_menu_set_loop)));
539         items.push_back (MenuElem (_("Set Punch Range"), mem_fun(*this, &Editor::new_transport_marker_menu_set_punch)));
540
541         new_transport_marker_menu->signal_unmap_event().connect ( mem_fun(*this, &Editor::new_transport_marker_menu_popdown)); 
542 }
543
544 void
545 Editor::marker_menu_hide ()
546 {
547         Marker* marker;
548
549         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
550                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
551                 /*NOTREACHED*/
552         }
553
554         Location* l;
555         bool is_start;
556         
557         if ((l = find_location_from_marker (marker, is_start)) != 0) {
558                 l->set_hidden (true, this);
559         }
560 }
561
562 void
563 Editor::marker_menu_select_all_selectables_using_range ()
564 {
565         Marker* marker;
566
567         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
568                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
569                 /*NOTREACHED*/
570         }
571
572         Location* l;
573         bool is_start;
574
575         if (((l = find_location_from_marker (marker, is_start)) != 0) && (l->end() > l->start())) {
576                 select_all_within (l->start(), l->end() - 1, 0,  DBL_MAX, Selection::Set);
577         }
578           
579 }
580
581 void
582 Editor::marker_menu_separate_regions_using_location ()
583 {
584         Marker* marker;
585
586         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
587                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
588                 /*NOTREACHED*/
589         }
590
591         Location* l;
592         bool is_start;
593
594         if (((l = find_location_from_marker (marker, is_start)) != 0) && (l->end() > l->start())) {
595                 separate_regions_using_location (*l);
596         }
597           
598 }
599
600 void
601 Editor::marker_menu_play_from ()
602 {
603         Marker* marker;
604
605         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
606                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
607                 /*NOTREACHED*/
608         }
609
610         Location* l;
611         bool is_start;
612         
613         if ((l = find_location_from_marker (marker, is_start)) != 0) {
614
615                 if (l->is_mark()) {
616                         session->request_locate (l->start(), true);
617                 }
618                 else {
619                         //session->request_bounded_roll (l->start(), l->end());
620                         
621                         if (is_start) {
622                                 session->request_locate (l->start(), true);
623                         } else {
624                                 session->request_locate (l->end(), true);
625                         }
626                 }
627         }
628 }
629
630 void
631 Editor::marker_menu_set_playhead ()
632 {
633         Marker* marker;
634
635         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
636                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
637                 /*NOTREACHED*/
638         }
639
640         Location* l;
641         bool is_start;
642         
643         if ((l = find_location_from_marker (marker, is_start)) != 0) {
644
645                 if (l->is_mark()) {
646                         session->request_locate (l->start(), false);
647                 }
648                 else {
649                         if (is_start) {
650                                 session->request_locate (l->start(), false);
651                         } else {
652                                 session->request_locate (l->end(), false);
653                         }
654                 }
655         }
656 }
657
658 void
659 Editor::marker_menu_set_from_playhead ()
660 {
661         Marker* marker;
662
663         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
664                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
665                 /*NOTREACHED*/
666         }
667
668         Location* l;
669         bool is_start;
670         
671         if ((l = find_location_from_marker (marker, is_start)) != 0) {
672
673                 if (l->is_mark()) {
674                         l->set_start (session->transport_frame ());
675                 }
676                 else {
677                         if (is_start) {
678                                 l->set_start (session->transport_frame ());
679                         } else {
680                                 l->set_end (session->transport_frame ());
681                         }
682                 }
683         }
684 }
685
686 void
687 Editor::marker_menu_set_from_selection ()
688 {
689         Marker* marker;
690
691         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
692                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
693                 /*NOTREACHED*/
694         }
695
696         Location* l;
697         bool is_start;
698         
699         if ((l = find_location_from_marker (marker, is_start)) != 0) {
700
701                 if (l->is_mark()) {
702                         // nothing for now
703                 }
704                 else {
705
706                         /* if range selection use first to last */
707
708                         if (mouse_mode == Editing::MouseRange) {
709                                 if (!selection->time.empty()) {
710                                         l->set_start (selection->time.start());
711                                         l->set_end (selection->time.end_frame());
712                                 }
713                         }
714                         else {
715                                 if (!selection->regions.empty()) {
716                                         l->set_start (selection->regions.start());
717                                         l->set_end (selection->regions.end_frame());
718                                 }
719                         }
720                 }
721         }
722 }
723
724
725 void
726 Editor::marker_menu_play_range ()
727 {
728         Marker* marker;
729
730         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
731                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
732                 /*NOTREACHED*/
733         }
734
735         Location* l;
736         bool is_start;
737         
738         if ((l = find_location_from_marker (marker, is_start)) != 0) {
739
740                 if (l->is_mark()) {
741                         session->request_locate (l->start(), true);
742                 }
743                 else {
744                         session->request_bounded_roll (l->start(), l->end());
745                         
746                 }
747         }
748 }
749
750 void
751 Editor::marker_menu_loop_range ()
752 {
753         Marker* marker;
754
755         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
756                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
757                 /*NOTREACHED*/
758         }
759
760         Location* l;
761         bool is_start;
762         
763         if ((l = find_location_from_marker (marker, is_start)) != 0) {
764                 Location* l2;
765                 if ((l2 = transport_loop_location()) != 0) {
766                         l2->set (l->start(), l->end());
767                         
768                         // enable looping, reposition and start rolling
769                         session->request_play_loop(true);
770                         session->request_locate (l2->start(), true);
771                 }
772         }
773 }
774
775 void
776 Editor::marker_menu_edit ()
777 {
778         MeterMarker* mm;
779         TempoMarker* tm;
780         Marker* marker;
781
782         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
783                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
784                 /*NOTREACHED*/
785         }
786
787         if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
788                 edit_meter_section (&mm->meter());
789         } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
790                 edit_tempo_section (&tm->tempo());
791         } else {
792                 fatal << X_("programming erorr: unhandled marker type in Editor::marker_menu_edit")
793                       << endmsg;
794                 /*NOTREACHED*/
795         }
796 }
797
798 void
799 Editor::marker_menu_remove ()
800 {
801         MeterMarker* mm;
802         TempoMarker* tm;
803         Marker* marker;
804
805         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
806                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
807                 /*NOTREACHED*/
808         }
809
810         if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
811                 remove_meter_marker (marker_menu_item);
812         } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
813                 remove_tempo_marker (marker_menu_item);
814         } else {
815                 remove_marker (*marker_menu_item, (GdkEvent*) 0);
816         }
817 }
818
819 void
820 Editor::marker_menu_rename ()
821 {
822         Marker* marker;
823
824         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
825                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
826                 /*NOTREACHED*/
827         }
828
829         Location* loc;
830         bool is_start;
831
832         loc = find_location_from_marker (marker, is_start);
833
834         if (!loc) return;
835         
836         ArdourPrompter dialog (true);
837         string txt;
838
839         dialog.set_prompt (_("New Name:"));
840         
841         if (loc->is_mark()) {
842                 dialog.set_title (_("ardour: rename mark"));
843         } else {
844                 dialog.set_title (_("ardour: rename range"));
845         }
846
847         dialog.set_name ("MarkRenameWindow");
848         dialog.set_size_request (250, -1);
849         dialog.set_position (Gtk::WIN_POS_MOUSE);
850
851         dialog.add_button (_("Rename"), RESPONSE_ACCEPT);
852         dialog.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
853         dialog.set_initial_text (loc->name());
854
855         dialog.show ();
856
857         switch (dialog.run ()) {
858         case RESPONSE_ACCEPT:
859                 break;
860         default:
861                 return;
862         }
863
864         begin_reversible_command ( _("rename marker") );
865         XMLNode &before = session->locations()->get_state();
866
867         dialog.get_result(txt);
868         loc->set_name (txt);
869         
870         XMLNode &after = session->locations()->get_state();
871         session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
872         commit_reversible_command ();
873 }
874
875 gint
876 Editor::new_transport_marker_menu_popdown (GdkEventAny *ev)
877 {
878         // hide rects
879         transport_bar_drag_rect->hide();
880         range_marker_drag_rect->hide();
881
882         return FALSE;
883 }
884
885 void
886 Editor::new_transport_marker_menu_set_loop ()
887 {
888         if (!session) return;
889         
890         begin_reversible_command (_("set loop range"));
891         
892         Location* tll;
893
894         if ((tll = transport_loop_location()) == 0) {
895                 Location* loc = new Location (temp_location->start(), temp_location->end(), _("Loop"),  Location::IsAutoLoop);
896                 XMLNode &before = session->locations()->get_state();
897                 session->locations()->add (loc, true);
898                 session->set_auto_loop_location (loc);
899                 XMLNode &after = session->locations()->get_state();
900                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
901         }
902         else {
903                 XMLNode &before = tll->get_state();
904                 tll->set_hidden (false, this);
905                 tll->set (temp_location->start(), temp_location->end());
906                 XMLNode &after = tll->get_state();
907                 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
908         }
909         
910         commit_reversible_command ();
911 }
912
913 void
914 Editor::new_transport_marker_menu_set_punch ()
915 {
916         if (!session) return;
917         
918         begin_reversible_command (_("set punch range"));
919         
920         Location* tpl;
921
922         if ((tpl = transport_punch_location()) == 0) {
923                 tpl = new Location (temp_location->start(), temp_location->end(), _("Punch"), Location::IsAutoPunch);
924                 XMLNode &before = session->locations()->get_state();
925                 session->locations()->add (tpl, true);
926                 session->set_auto_punch_location (tpl);
927                 XMLNode &after = session->locations()->get_state();
928                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
929         } else {
930                 XMLNode &before = tpl->get_state();
931                 tpl->set_hidden(false, this);
932                 tpl->set(temp_location->start(), temp_location->end());
933                 XMLNode &after = tpl->get_state();
934                 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
935         }
936         
937         commit_reversible_command ();
938 }
939
940 void
941 Editor::update_loop_range_view (bool visibility)
942 {
943         if (session == 0) {
944                 return;
945         }
946
947         Location* tll;
948
949         if (session->get_play_loop() && ((tll = transport_loop_location()) != 0)) {
950
951                 double x1 = frame_to_pixel (tll->start());
952                 double x2 = frame_to_pixel (tll->end());
953                 
954                 transport_loop_range_rect->property_x1() = x1;
955                 transport_loop_range_rect->property_x2() = x2;
956                 
957                 if (visibility) {
958                         transport_loop_range_rect->show();
959                 }
960         }
961         else if (visibility) {
962                 transport_loop_range_rect->hide();
963         }
964 }
965
966 void
967 Editor::update_punch_range_view (bool visibility)
968 {
969         if (session == 0) {
970                 return;
971         }
972
973         Location* tpl;
974
975         if ((Config->get_punch_in() || Config->get_punch_out()) && ((tpl = transport_punch_location()) != 0)) {
976
977                 double x1 = frame_to_pixel (tpl->start());
978                 double x2 = frame_to_pixel (tpl->end());
979                 
980                 transport_punch_range_rect->property_x1() = x1;
981                 transport_punch_range_rect->property_x2() = x2;
982                 
983                 if (visibility) {
984                         transport_punch_range_rect->show();
985                 }
986         }
987         else if (visibility) {
988                 transport_punch_range_rect->hide();
989         }
990
991 //      if (session->get_punch_in()) {
992 //              double x = frame_to_pixel (transport_punch_location->start());
993 //              gnome_canvas_item_set (transport_punchin_line, "x1", x, "x2", x, NULL);
994                 
995 //              if (visibility) {
996 //                      gnome_canvas_item_show (transport_punchin_line);
997 //              }
998 //      }
999 //      else if (visibility) {
1000 //              gnome_canvas_item_hide (transport_punchin_line);
1001 //      }
1002         
1003 //      if (session->get_punch_out()) {
1004 //              double x = frame_to_pixel (transport_punch_location->end());
1005                 
1006 //              gnome_canvas_item_set (transport_punchout_line, "x1", x, "x2", x, NULL);
1007                 
1008 //              if (visibility) {
1009 //                      gnome_canvas_item_show (transport_punchout_line);
1010 //              }
1011 //      }
1012 //      else if (visibility) {
1013 //              gnome_canvas_item_hide (transport_punchout_line);
1014 //      }
1015 }