Merged with trunk R846
[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 (jack_nframes_t startf, 
275                                        jack_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 (jack_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 (_("Loop Range"), mem_fun(*this, &Editor::marker_menu_loop_range)));
485         items.push_back (MenuElem (_("Set Range Mark from Playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
486         items.push_back (MenuElem (_("Set Range from Range Selection"), mem_fun(*this, &Editor::marker_menu_set_from_selection)));
487
488         items.push_back (SeparatorElem());
489
490         items.push_back (MenuElem (_("Rename Range"), mem_fun(*this, &Editor::marker_menu_rename)));
491         items.push_back (MenuElem (_("Hide Range"), mem_fun(*this, &Editor::marker_menu_hide)));
492         items.push_back (MenuElem (_("Remove Range"), mem_fun(*this, &Editor::marker_menu_remove)));
493
494         items.push_back (SeparatorElem());
495
496         items.push_back (MenuElem (_("Separate Regions in Range"), mem_fun(*this, &Editor::marker_menu_separate_regions_using_location)));
497         items.push_back (MenuElem (_("Select All in Range"), mem_fun(*this, &Editor::marker_menu_select_all_selectables_using_range)));
498
499 }
500
501 void
502 Editor::build_tm_marker_menu ()
503 {
504         using namespace Menu_Helpers;
505
506         tm_marker_menu = new Menu;
507         MenuList& items = tm_marker_menu->items();
508         tm_marker_menu->set_name ("ArdourContextMenu");
509
510         items.push_back (MenuElem (_("Edit"), mem_fun(*this, &Editor::marker_menu_edit)));
511         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::marker_menu_remove)));
512 }
513
514 void
515 Editor::build_new_transport_marker_menu ()
516 {
517         using namespace Menu_Helpers;
518
519         new_transport_marker_menu = new Menu;
520         MenuList& items = new_transport_marker_menu->items();
521         new_transport_marker_menu->set_name ("ArdourContextMenu");
522
523         items.push_back (MenuElem (_("Set Loop Range"), mem_fun(*this, &Editor::new_transport_marker_menu_set_loop)));
524         items.push_back (MenuElem (_("Set Punch Range"), mem_fun(*this, &Editor::new_transport_marker_menu_set_punch)));
525
526         new_transport_marker_menu->signal_unmap_event().connect ( mem_fun(*this, &Editor::new_transport_marker_menu_popdown)); 
527 }
528
529 void
530 Editor::build_transport_marker_menu ()
531 {
532         using namespace Menu_Helpers;
533
534         transport_marker_menu = new Menu;
535         MenuList& items = transport_marker_menu->items();
536         transport_marker_menu->set_name ("ArdourContextMenu");
537
538         items.push_back (MenuElem (_("Locate to Range Mark"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
539         items.push_back (MenuElem (_("Play from Range Mark"), mem_fun(*this, &Editor::marker_menu_play_from)));
540         items.push_back (MenuElem (_("Set Range Mark from Playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
541         items.push_back (MenuElem (_("Set Range from Range Selection"), mem_fun(*this, &Editor::marker_menu_set_from_selection)));
542         items.push_back (SeparatorElem());
543         items.push_back (MenuElem (_("Hide Range"), mem_fun(*this, &Editor::marker_menu_hide)));
544         items.push_back (SeparatorElem());
545         items.push_back (MenuElem (_("Separate Regions in Range"), mem_fun(*this, &Editor::marker_menu_separate_regions_using_location)));
546         items.push_back (MenuElem (_("Select All in Range"), mem_fun(*this, &Editor::marker_menu_select_all_selectables_using_range)));
547 }
548
549 void
550 Editor::marker_menu_hide ()
551 {
552         Marker* marker;
553
554         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
555                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
556                 /*NOTREACHED*/
557         }
558
559         Location* l;
560         bool is_start;
561         
562         if ((l = find_location_from_marker (marker, is_start)) != 0) {
563                 l->set_hidden (true, this);
564         }
565 }
566
567 void
568 Editor::marker_menu_select_all_selectables_using_range ()
569 {
570         Marker* marker;
571
572         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
573                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
574                 /*NOTREACHED*/
575         }
576
577         Location* l;
578         bool is_start;
579
580         if (((l = find_location_from_marker (marker, is_start)) != 0) && (l->end() > l->start())) {
581                 select_all_within (l->start(), l->end() - 1, 0,  DBL_MAX, Selection::Set);
582         }
583           
584 }
585
586 void
587 Editor::marker_menu_separate_regions_using_location ()
588 {
589         Marker* marker;
590
591         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
592                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
593                 /*NOTREACHED*/
594         }
595
596         Location* l;
597         bool is_start;
598
599         if (((l = find_location_from_marker (marker, is_start)) != 0) && (l->end() > l->start())) {
600                 separate_regions_using_location (*l);
601         }
602           
603 }
604
605 void
606 Editor::marker_menu_play_from ()
607 {
608         Marker* marker;
609
610         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
611                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
612                 /*NOTREACHED*/
613         }
614
615         Location* l;
616         bool is_start;
617         
618         if ((l = find_location_from_marker (marker, is_start)) != 0) {
619
620                 if (l->is_mark()) {
621                         session->request_locate (l->start(), true);
622                 }
623                 else {
624                         //session->request_bounded_roll (l->start(), l->end());
625                         
626                         if (is_start) {
627                                 session->request_locate (l->start(), true);
628                         } else {
629                                 session->request_locate (l->end(), true);
630                         }
631                 }
632         }
633 }
634
635 void
636 Editor::marker_menu_set_playhead ()
637 {
638         Marker* marker;
639
640         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
641                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
642                 /*NOTREACHED*/
643         }
644
645         Location* l;
646         bool is_start;
647         
648         if ((l = find_location_from_marker (marker, is_start)) != 0) {
649
650                 if (l->is_mark()) {
651                         session->request_locate (l->start(), false);
652                 }
653                 else {
654                         if (is_start) {
655                                 session->request_locate (l->start(), false);
656                         } else {
657                                 session->request_locate (l->end(), false);
658                         }
659                 }
660         }
661 }
662
663 void
664 Editor::marker_menu_set_from_playhead ()
665 {
666         Marker* marker;
667
668         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
669                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
670                 /*NOTREACHED*/
671         }
672
673         Location* l;
674         bool is_start;
675         
676         if ((l = find_location_from_marker (marker, is_start)) != 0) {
677
678                 if (l->is_mark()) {
679                         l->set_start (session->transport_frame ());
680                 }
681                 else {
682                         if (is_start) {
683                                 l->set_start (session->transport_frame ());
684                         } else {
685                                 l->set_end (session->transport_frame ());
686                         }
687                 }
688         }
689 }
690
691 void
692 Editor::marker_menu_set_from_selection ()
693 {
694         Marker* marker;
695
696         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
697                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
698                 /*NOTREACHED*/
699         }
700
701         Location* l;
702         bool is_start;
703         
704         if ((l = find_location_from_marker (marker, is_start)) != 0) {
705
706                 if (l->is_mark()) {
707                         // nothing for now
708                 }
709                 else {
710
711                         /* if range selection use first to last */
712
713                         if (mouse_mode == Editing::MouseRange) {
714                                 if (!selection->time.empty()) {
715                                         l->set_start (selection->time.start());
716                                         l->set_end (selection->time.end_frame());
717                                 }
718                         }
719                         else {
720                                 if (!selection->regions.empty()) {
721                                         l->set_start (selection->regions.start());
722                                         l->set_end (selection->regions.end_frame());
723                                 }
724                         }
725                 }
726         }
727 }
728
729 void
730 Editor::marker_menu_loop_range ()
731 {
732         Marker* marker;
733
734         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
735                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
736                 /*NOTREACHED*/
737         }
738
739         Location* l;
740         bool is_start;
741         
742         if ((l = find_location_from_marker (marker, is_start)) != 0) {
743                 Location* l2;
744                 if ((l2 = transport_loop_location()) != 0) {
745                         l2->set (l->start(), l->end());
746                         
747                         // enable looping, reposition and start rolling
748                         session->request_auto_loop(true);
749                         session->request_locate (l2->start(), true);
750                 }
751         }
752 }
753
754 void
755 Editor::marker_menu_edit ()
756 {
757         MeterMarker* mm;
758         TempoMarker* tm;
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         if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
767                 edit_meter_section (&mm->meter());
768         } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
769                 edit_tempo_section (&tm->tempo());
770         } else {
771                 fatal << X_("programming erorr: unhandled marker type in Editor::marker_menu_edit")
772                       << endmsg;
773                 /*NOTREACHED*/
774         }
775 }
776
777 void
778 Editor::marker_menu_remove ()
779 {
780         MeterMarker* mm;
781         TempoMarker* tm;
782         Marker* marker;
783
784         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
785                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
786                 /*NOTREACHED*/
787         }
788
789         if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
790                 remove_meter_marker (marker_menu_item);
791         } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
792                 remove_tempo_marker (marker_menu_item);
793         } else {
794                 remove_marker (*marker_menu_item, (GdkEvent*) 0);
795         }
796 }
797
798 void
799 Editor::marker_menu_rename ()
800 {
801         Marker* marker;
802
803         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
804                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
805                 /*NOTREACHED*/
806         }
807
808         Location* loc;
809         bool is_start;
810
811         loc = find_location_from_marker (marker, is_start);
812
813         if (!loc) return;
814         
815         ArdourPrompter dialog (true);
816         string txt;
817
818         dialog.set_prompt (_("New Name:"));
819         
820         if (loc->is_mark()) {
821                 dialog.set_title (_("ardour: rename mark"));
822         } else {
823                 dialog.set_title (_("ardour: rename range"));
824         }
825
826         dialog.set_name ("MarkRenameWindow");
827         dialog.set_size_request (250, -1);
828         dialog.set_position (Gtk::WIN_POS_MOUSE);
829
830         dialog.add_button (_("Rename"), RESPONSE_ACCEPT);
831         dialog.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
832         dialog.set_initial_text (loc->name());
833
834         dialog.show ();
835
836         switch (dialog.run ()) {
837         case RESPONSE_ACCEPT:
838                 break;
839         default:
840                 return;
841         }
842
843         begin_reversible_command ( _("rename marker") );
844         XMLNode &before = session->locations()->get_state();
845
846         dialog.get_result(txt);
847         loc->set_name (txt);
848         
849         XMLNode &after = session->locations()->get_state();
850         session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
851         commit_reversible_command ();
852 }
853
854 gint
855 Editor::new_transport_marker_menu_popdown (GdkEventAny *ev)
856 {
857         // hide rects
858         transport_bar_drag_rect->hide();
859         range_marker_drag_rect->hide();
860
861         return FALSE;
862 }
863
864 void
865 Editor::new_transport_marker_menu_set_loop ()
866 {
867         if (!session) return;
868         
869         begin_reversible_command (_("set loop range"));
870         
871         Location* tll;
872
873         if ((tll = transport_loop_location()) == 0) {
874                 Location* loc = new Location (temp_location->start(), temp_location->end(), _("Loop"),  Location::IsAutoLoop);
875                 XMLNode &before = session->locations()->get_state();
876                 session->locations()->add (loc, true);
877                 session->set_auto_loop_location (loc);
878                 XMLNode &after = session->locations()->get_state();
879                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
880         }
881         else {
882                 XMLNode &before = tll->get_state();
883                 tll->set_hidden (false, this);
884                 tll->set (temp_location->start(), temp_location->end());
885                 XMLNode &after = tll->get_state();
886                 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
887         }
888         
889         commit_reversible_command ();
890 }
891
892 void
893 Editor::new_transport_marker_menu_set_punch ()
894 {
895         if (!session) return;
896         
897         begin_reversible_command (_("set punch range"));
898         
899         Location* tpl;
900
901         if ((tpl = transport_punch_location()) == 0) {
902                 tpl = new Location (temp_location->start(), temp_location->end(), _("Punch"), Location::IsAutoPunch);
903                 XMLNode &before = session->locations()->get_state();
904                 session->locations()->add (tpl, true);
905                 session->set_auto_punch_location (tpl);
906                 XMLNode &after = session->locations()->get_state();
907                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
908         } else {
909                 XMLNode &before = tpl->get_state();
910                 tpl->set_hidden(false, this);
911                 tpl->set(temp_location->start(), temp_location->end());
912                 XMLNode &after = tpl->get_state();
913                 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
914         }
915         
916         commit_reversible_command ();
917 }
918
919 void
920 Editor::update_loop_range_view (bool visibility)
921 {
922         if (session == 0) {
923                 return;
924         }
925
926         Location* tll;
927
928         if (session->get_auto_loop() && ((tll = transport_loop_location()) != 0)) {
929
930                 double x1 = frame_to_pixel (tll->start());
931                 double x2 = frame_to_pixel (tll->end());
932                 
933                 transport_loop_range_rect->property_x1() = x1;
934                 transport_loop_range_rect->property_x2() = x2;
935                 
936                 if (visibility) {
937                         transport_loop_range_rect->show();
938                 }
939         }
940         else if (visibility) {
941                 transport_loop_range_rect->hide();
942         }
943 }
944
945 void
946 Editor::update_punch_range_view (bool visibility)
947 {
948         if (session == 0) {
949                 return;
950         }
951
952         Location* tpl;
953
954         if ((session->get_punch_in() || session->get_punch_out()) && ((tpl = transport_punch_location()) != 0)) {
955
956                 double x1 = frame_to_pixel (tpl->start());
957                 double x2 = frame_to_pixel (tpl->end());
958                 
959                 transport_punch_range_rect->property_x1() = x1;
960                 transport_punch_range_rect->property_x2() = x2;
961                 
962                 if (visibility) {
963                         transport_punch_range_rect->show();
964                 }
965         }
966         else if (visibility) {
967                 transport_punch_range_rect->hide();
968         }
969
970 //      if (session->get_punch_in()) {
971 //              double x = frame_to_pixel (transport_punch_location->start());
972 //              gnome_canvas_item_set (transport_punchin_line, "x1", x, "x2", x, NULL);
973                 
974 //              if (visibility) {
975 //                      gnome_canvas_item_show (transport_punchin_line);
976 //              }
977 //      }
978 //      else if (visibility) {
979 //              gnome_canvas_item_hide (transport_punchin_line);
980 //      }
981         
982 //      if (session->get_punch_out()) {
983 //              double x = frame_to_pixel (transport_punch_location->end());
984                 
985 //              gnome_canvas_item_set (transport_punchout_line, "x1", x, "x2", x, NULL);
986                 
987 //              if (visibility) {
988 //                      gnome_canvas_item_show (transport_punchout_line);
989 //              }
990 //      }
991 //      else if (visibility) {
992 //              gnome_canvas_item_hide (transport_punchout_line);
993 //      }
994 }