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