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