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