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