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