patches from Stephane Letz for JACK, and Nimal Ratnayake for play range and play...
[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 #include <pbd/memento_command.h>
30
31 #include "editor.h"
32 #include "marker.h"
33 #include "selection.h"
34 #include "editing.h"
35 #include "gui_thread.h"
36 #include "simplerect.h"
37 #include "actions.h"
38 #include "prompter.h"
39
40 #include "i18n.h"
41
42 using namespace std;
43 using namespace sigc;
44 using namespace ARDOUR;
45 using namespace PBD;
46 using namespace Gtk;
47
48 void
49 Editor::clear_marker_display ()
50 {
51         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
52                 delete i->second;
53         }
54
55         location_markers.clear ();
56 }
57
58 void
59 Editor::add_new_location (Location *location)
60 {
61         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::add_new_location), location));
62
63         LocationMarkers *lam = new LocationMarkers;
64         uint32_t color;
65
66         if (location->is_cd_marker()) {
67                 color = location_cd_marker_color;
68         } else if (location->is_mark()) {
69                 color = location_marker_color;
70         } else if (location->is_auto_loop()) {
71                 color = location_loop_color;
72         } else if (location->is_auto_punch()) {
73                 color = location_punch_color;
74         } else {
75                 color = location_range_color;
76         }
77
78         if (location->is_mark()) {
79                 lam->start = new Marker (*this, *marker_group, color, location->name(), Marker::Mark, location->start());
80                 lam->end   = 0;
81
82         } else if (location->is_auto_loop()) {
83                 // transport marker
84                 lam->start = new Marker (*this, *transport_marker_group, color, 
85                                          location->name(), Marker::LoopStart, location->start());
86                 lam->end   = new Marker (*this, *transport_marker_group, color, 
87                                          location->name(), Marker::LoopEnd, location->end());
88                 
89         } else if (location->is_auto_punch()) {
90                 // transport marker
91                 lam->start = new Marker (*this, *transport_marker_group, color, 
92                                          location->name(), Marker::PunchIn, location->start());
93                 lam->end   = new Marker (*this, *transport_marker_group, color, 
94                                          location->name(), Marker::PunchOut, location->end());
95                 
96         } else {
97
98                 // range marker
99                 lam->start = new Marker (*this, *range_marker_group, color, 
100                                          location->name(), Marker::Start, location->start());
101                 lam->end   = new Marker (*this, *range_marker_group, color, 
102                                          location->name(), Marker::End, location->end());
103         }
104
105         if (location->is_hidden ()) {
106                 lam->hide();
107         } else {
108                 lam->show ();
109         }
110
111         location->start_changed.connect (mem_fun(*this, &Editor::location_changed));
112         location->end_changed.connect (mem_fun(*this, &Editor::location_changed));
113         location->changed.connect (mem_fun(*this, &Editor::location_changed));
114         location->name_changed.connect (mem_fun(*this, &Editor::location_changed));
115         location->FlagsChanged.connect (mem_fun(*this, &Editor::location_flags_changed));
116
117         pair<Location*,LocationMarkers*> newpair;
118
119         newpair.first = location;
120         newpair.second = lam;
121
122         location_markers.insert (newpair);
123 }
124
125 void
126 Editor::location_changed (Location *location)
127 {
128         ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::location_changed), location));
129
130         LocationMarkers *lam = find_location_markers (location);
131
132         if (lam == 0) {
133                 /* a location that isn't "marked" with markers */
134                 return;
135         }
136         
137         lam->set_name (location->name());
138         lam->set_position (location->start(), location->end());
139
140         if (location->is_auto_loop()) {
141                 update_loop_range_view ();
142         } else if (location->is_auto_punch()) {
143                 update_punch_range_view ();
144         }
145 }
146
147 void
148 Editor::location_flags_changed (Location *location, void *src)
149 {
150         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::location_flags_changed), location, src));
151         
152         LocationMarkers *lam = find_location_markers (location);
153         
154         if (lam == 0) {
155                 /* a location that isn't "marked" with markers */
156                 return;
157         }
158
159         if (location->is_cd_marker()) {
160                 lam->set_color_rgba (location_cd_marker_color);
161         } else if (location->is_mark()) {
162                 lam->set_color_rgba (location_marker_color);
163         } else if (location->is_auto_punch()) {
164                 lam->set_color_rgba (location_punch_color);
165         } else if (location->is_auto_loop()) {
166                 lam->set_color_rgba (location_loop_color);
167         } else {
168                 lam->set_color_rgba (location_range_color);
169         }
170         
171         if (location->is_hidden()) {
172                 lam->hide();
173         } else {
174                 lam->show ();
175         }
176 }
177
178 Editor::LocationMarkers::~LocationMarkers ()
179 {
180         if (start) {
181                 delete start;
182         }
183
184         if (end) {
185                 delete end;
186         }
187 }
188
189 Editor::LocationMarkers *
190 Editor::find_location_markers (Location *location)
191 {
192         LocationMarkerMap::iterator i;
193
194         for (i = location_markers.begin(); i != location_markers.end(); ++i) {
195                 if ((*i).first == location) {
196                         return (*i).second;
197                 }
198         }
199
200         return 0;
201 }
202
203 Location *
204 Editor::find_location_from_marker (Marker *marker, bool& is_start)
205 {
206         LocationMarkerMap::iterator i;
207
208         for (i = location_markers.begin(); i != location_markers.end(); ++i) {
209                 LocationMarkers *lm = (*i).second;
210                 if (lm->start == marker) {
211                         is_start = true;
212                         return (*i).first;
213                 } else if (lm->end == marker) {
214                         is_start = false;
215                         return (*i).first;
216                 }
217         }
218
219         return 0;
220 }
221
222 void
223 Editor::refresh_location_display_internal (Locations::LocationList& locations)
224 {
225         clear_marker_display ();
226         
227         for (Locations::LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
228                 add_new_location (*i);
229         }
230 }
231
232 void
233 Editor::refresh_location_display ()
234 {
235         ENSURE_GUI_THREAD(mem_fun(*this, &Editor::refresh_location_display));
236         
237         if (session) {
238                 session->locations()->apply (*this, &Editor::refresh_location_display_internal);
239         }
240 }
241
242 void
243 Editor::refresh_location_display_s (Change ignored)
244 {
245         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::refresh_location_display_s), ignored));
246
247         if (session) {
248                 session->locations()->apply (*this, &Editor::refresh_location_display_internal);
249         }
250 }
251
252 void
253 Editor::LocationMarkers::hide() 
254 {
255         start->hide ();
256         if (end) { end->hide(); }
257 }
258
259 void
260 Editor::LocationMarkers::show() 
261 {
262         start->show ();
263         if (end) { end->show(); }
264 }
265
266 void
267 Editor::LocationMarkers::set_name (const string& str) 
268 {
269         start->set_name (str);
270         if (end) { end->set_name (str); }
271 }
272
273 void
274 Editor::LocationMarkers::set_position (nframes_t startf, 
275                                        nframes_t endf) 
276 {
277         start->set_position (startf);
278         if (end) { end->set_position (endf); }
279 }
280
281 void
282 Editor::LocationMarkers::set_color_rgba (uint32_t rgba) 
283 {
284         start->set_color_rgba (rgba);
285         if (end) { end->set_color_rgba (rgba); }
286 }
287
288 void
289 Editor::mouse_add_new_marker (nframes_t where)
290 {
291         if (session) {
292                 Location *location = new Location (where, where, "mark", Location::IsMark);
293                 session->begin_reversible_command (_("add marker"));
294                 XMLNode &before = session->locations()->get_state();
295                 session->locations()->add (location, true);
296                 XMLNode &after = session->locations()->get_state();
297                 session->add_command (new 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 = session->locations()->get_state();
335         session->locations()->remove (loc);
336         XMLNode &after = session->locations()->get_state();
337         session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
338         session->commit_reversible_command ();
339         return FALSE;
340 }
341
342 void
343 Editor::location_gone (Location *location)
344 {
345         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::location_gone), location));
346         
347         LocationMarkerMap::iterator i;
348
349         if (location == transport_loop_location()) {
350                 update_loop_range_view (true);
351         }
352
353         if (location == transport_punch_location()) {
354                 update_punch_range_view (true);
355         }
356         
357         for (i = location_markers.begin(); i != location_markers.end(); ++i) {
358                 if ((*i).first == location) {
359                         delete (*i).second;
360                         location_markers.erase (i);
361                         break;
362                 }
363         }
364 }
365
366 void
367 Editor::tm_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
368 {
369         if (tm_marker_menu == 0) {
370                 build_tm_marker_menu ();
371         }
372
373         marker_menu_item = item;
374         tm_marker_menu->popup (1, ev->time);
375
376 }
377
378 void
379 Editor::marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
380 {
381         Marker * marker;
382         if ((marker = reinterpret_cast<Marker *> (item->get_data("marker"))) == 0) {
383                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
384                 /*NOTREACHED*/
385         }
386         
387         bool is_start;
388         Location * loc = find_location_from_marker (marker, is_start);
389         if (loc == transport_loop_location() || loc == transport_punch_location()) {
390                 if (transport_marker_menu == 0) {
391                         build_transport_marker_menu ();
392                 }
393                 marker_menu_item = item;
394                 transport_marker_menu->popup (1, ev->time);
395         } else {
396
397                 if (loc->is_mark()) {
398                        if (marker_menu == 0) {
399                               build_marker_menu ();
400                        }
401
402
403                 // GTK2FIX use action group sensitivity
404 #ifdef GTK2FIX
405                 if (children.size() >= 3) {
406                         MenuItem * loopitem = &children[2];
407                         if (loopitem) {
408                                 if (loc->is_mark()) {
409                                         loopitem->set_sensitive(false);
410                                 }
411                                 else {
412                                         loopitem->set_sensitive(true);
413                                 }
414                         }
415                 }
416 #endif          
417                 marker_menu_item = item;
418                 marker_menu->popup (1, ev->time);
419                 }
420
421                 if (loc->is_range_marker()) {
422                        if (range_marker_menu == 0){
423                               build_range_marker_menu ();
424                        }
425                        marker_menu_item = item;
426                        range_marker_menu->popup (1, ev->time);
427                 }
428         }
429 }
430
431 void
432 Editor::new_transport_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
433 {
434         if (new_transport_marker_menu == 0) {
435                 build_new_transport_marker_menu ();
436         }
437
438         new_transport_marker_menu->popup (1, ev->time);
439
440 }
441
442 void
443 Editor::transport_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
444 {
445         if (transport_marker_menu == 0) {
446                 build_transport_marker_menu ();
447         }
448
449         transport_marker_menu->popup (1, ev->time);
450 }
451
452 void
453 Editor::build_marker_menu ()
454 {
455         using namespace Menu_Helpers;
456
457         marker_menu = new Menu;
458         MenuList& items = marker_menu->items();
459         marker_menu->set_name ("ArdourContextMenu");
460
461         items.push_back (MenuElem (_("Locate to Mark"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
462         items.push_back (MenuElem (_("Play from Mark"), mem_fun(*this, &Editor::marker_menu_play_from)));
463         items.push_back (MenuElem (_("Set Mark from Playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
464
465         items.push_back (SeparatorElem());
466
467         items.push_back (MenuElem (_("Rename Mark"), mem_fun(*this, &Editor::marker_menu_rename)));
468         items.push_back (MenuElem (_("Hide Mark"), mem_fun(*this, &Editor::marker_menu_hide)));
469         items.push_back (MenuElem (_("Remove Mark"), mem_fun(*this, &Editor::marker_menu_remove)));
470
471 }
472
473 void
474 Editor::build_range_marker_menu ()
475 {
476         using namespace Menu_Helpers;
477
478         range_marker_menu = new Menu;
479         MenuList& items = range_marker_menu->items();
480         range_marker_menu->set_name ("ArdourContextMenu");
481
482         items.push_back (MenuElem (_("Locate to Range Mark"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
483         items.push_back (MenuElem (_("Play from Range Mark"), mem_fun(*this, &Editor::marker_menu_play_from)));
484         items.push_back (MenuElem (_("Play Range"), mem_fun(*this, &Editor::marker_menu_play_range)));
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->regions.empty()) {
722                                         l->set_start (selection->regions.start());
723                                         l->set_end (selection->regions.end_frame());
724                                 }
725                         }
726                 }
727         }
728 }
729
730
731 void
732 Editor::marker_menu_play_range ()
733 {
734         Marker* marker;
735
736         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
737                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
738                 /*NOTREACHED*/
739         }
740
741         Location* l;
742         bool is_start;
743         
744         if ((l = find_location_from_marker (marker, is_start)) != 0) {
745
746                 if (l->is_mark()) {
747                         session->request_locate (l->start(), true);
748                 }
749                 else {
750                         session->request_bounded_roll (l->start(), l->end());
751                         
752                 }
753         }
754 }
755
756 void
757 Editor::marker_menu_loop_range ()
758 {
759         Marker* marker;
760
761         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
762                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
763                 /*NOTREACHED*/
764         }
765
766         Location* l;
767         bool is_start;
768         
769         if ((l = find_location_from_marker (marker, is_start)) != 0) {
770                 Location* l2;
771                 if ((l2 = transport_loop_location()) != 0) {
772                         l2->set (l->start(), l->end());
773                         
774                         // enable looping, reposition and start rolling
775                         session->request_play_loop(true);
776                         session->request_locate (l2->start(), true);
777                 }
778         }
779 }
780
781 void
782 Editor::marker_menu_edit ()
783 {
784         MeterMarker* mm;
785         TempoMarker* tm;
786         Marker* marker;
787
788         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
789                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
790                 /*NOTREACHED*/
791         }
792
793         if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
794                 edit_meter_section (&mm->meter());
795         } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
796                 edit_tempo_section (&tm->tempo());
797         } else {
798                 fatal << X_("programming erorr: unhandled marker type in Editor::marker_menu_edit")
799                       << endmsg;
800                 /*NOTREACHED*/
801         }
802 }
803
804 void
805 Editor::marker_menu_remove ()
806 {
807         MeterMarker* mm;
808         TempoMarker* tm;
809         Marker* marker;
810
811         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
812                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
813                 /*NOTREACHED*/
814         }
815
816         if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
817                 remove_meter_marker (marker_menu_item);
818         } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
819                 remove_tempo_marker (marker_menu_item);
820         } else {
821                 remove_marker (*marker_menu_item, (GdkEvent*) 0);
822         }
823 }
824
825 void
826 Editor::marker_menu_rename ()
827 {
828         Marker* marker;
829
830         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
831                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
832                 /*NOTREACHED*/
833         }
834
835         Location* loc;
836         bool is_start;
837
838         loc = find_location_from_marker (marker, is_start);
839
840         if (!loc) return;
841         
842         ArdourPrompter dialog (true);
843         string txt;
844
845         dialog.set_prompt (_("New Name:"));
846         
847         if (loc->is_mark()) {
848                 dialog.set_title (_("ardour: rename mark"));
849         } else {
850                 dialog.set_title (_("ardour: rename range"));
851         }
852
853         dialog.set_name ("MarkRenameWindow");
854         dialog.set_size_request (250, -1);
855         dialog.set_position (Gtk::WIN_POS_MOUSE);
856
857         dialog.add_button (_("Rename"), RESPONSE_ACCEPT);
858         dialog.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
859         dialog.set_initial_text (loc->name());
860
861         dialog.show ();
862
863         switch (dialog.run ()) {
864         case RESPONSE_ACCEPT:
865                 break;
866         default:
867                 return;
868         }
869
870         begin_reversible_command ( _("rename marker") );
871         XMLNode &before = session->locations()->get_state();
872
873         dialog.get_result(txt);
874         loc->set_name (txt);
875         
876         XMLNode &after = session->locations()->get_state();
877         session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
878         commit_reversible_command ();
879 }
880
881 gint
882 Editor::new_transport_marker_menu_popdown (GdkEventAny *ev)
883 {
884         // hide rects
885         transport_bar_drag_rect->hide();
886         range_marker_drag_rect->hide();
887
888         return FALSE;
889 }
890
891 void
892 Editor::new_transport_marker_menu_set_loop ()
893 {
894         if (!session) return;
895         
896         begin_reversible_command (_("set loop range"));
897         
898         Location* tll;
899
900         if ((tll = transport_loop_location()) == 0) {
901                 Location* loc = new Location (temp_location->start(), temp_location->end(), _("Loop"),  Location::IsAutoLoop);
902                 XMLNode &before = session->locations()->get_state();
903                 session->locations()->add (loc, true);
904                 session->set_auto_loop_location (loc);
905                 XMLNode &after = session->locations()->get_state();
906                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
907         }
908         else {
909                 XMLNode &before = tll->get_state();
910                 tll->set_hidden (false, this);
911                 tll->set (temp_location->start(), temp_location->end());
912                 XMLNode &after = tll->get_state();
913                 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
914         }
915         
916         commit_reversible_command ();
917 }
918
919 void
920 Editor::new_transport_marker_menu_set_punch ()
921 {
922         if (!session) return;
923         
924         begin_reversible_command (_("set punch range"));
925         
926         Location* tpl;
927
928         if ((tpl = transport_punch_location()) == 0) {
929                 tpl = new Location (temp_location->start(), temp_location->end(), _("Punch"), Location::IsAutoPunch);
930                 XMLNode &before = session->locations()->get_state();
931                 session->locations()->add (tpl, true);
932                 session->set_auto_punch_location (tpl);
933                 XMLNode &after = session->locations()->get_state();
934                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
935         } else {
936                 XMLNode &before = tpl->get_state();
937                 tpl->set_hidden(false, this);
938                 tpl->set(temp_location->start(), temp_location->end());
939                 XMLNode &after = tpl->get_state();
940                 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
941         }
942         
943         commit_reversible_command ();
944 }
945
946 void
947 Editor::update_loop_range_view (bool visibility)
948 {
949         if (session == 0) {
950                 return;
951         }
952
953         Location* tll;
954
955         if (session->get_play_loop() && ((tll = transport_loop_location()) != 0)) {
956
957                 double x1 = frame_to_pixel (tll->start());
958                 double x2 = frame_to_pixel (tll->end());
959                 
960                 transport_loop_range_rect->property_x1() = x1;
961                 transport_loop_range_rect->property_x2() = x2;
962                 
963                 if (visibility) {
964                         transport_loop_range_rect->show();
965                 }
966         }
967         else if (visibility) {
968                 transport_loop_range_rect->hide();
969         }
970 }
971
972 void
973 Editor::update_punch_range_view (bool visibility)
974 {
975         if (session == 0) {
976                 return;
977         }
978
979         Location* tpl;
980
981         if ((Config->get_punch_in() || Config->get_punch_out()) && ((tpl = transport_punch_location()) != 0)) {
982
983                 double x1 = frame_to_pixel (tpl->start());
984                 double x2 = frame_to_pixel (tpl->end());
985                 
986                 transport_punch_range_rect->property_x1() = x1;
987                 transport_punch_range_rect->property_x2() = x2;
988                 
989                 if (visibility) {
990                         transport_punch_range_rect->show();
991                 }
992         }
993         else if (visibility) {
994                 transport_punch_range_rect->hide();
995         }
996
997 //      if (session->get_punch_in()) {
998 //              double x = frame_to_pixel (transport_punch_location->start());
999 //              gnome_canvas_item_set (transport_punchin_line, "x1", x, "x2", x, NULL);
1000                 
1001 //              if (visibility) {
1002 //                      gnome_canvas_item_show (transport_punchin_line);
1003 //              }
1004 //      }
1005 //      else if (visibility) {
1006 //              gnome_canvas_item_hide (transport_punchin_line);
1007 //      }
1008         
1009 //      if (session->get_punch_out()) {
1010 //              double x = frame_to_pixel (transport_punch_location->end());
1011                 
1012 //              gnome_canvas_item_set (transport_punchout_line, "x1", x, "x2", x, NULL);
1013                 
1014 //              if (visibility) {
1015 //                      gnome_canvas_item_show (transport_punchout_line);
1016 //              }
1017 //      }
1018 //      else if (visibility) {
1019 //              gnome_canvas_item_hide (transport_punchout_line);
1020 //      }
1021 }