Merged with trunk R1612.
[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
27 #include <ardour/location.h>
28 #include <pbd/memento_command.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 (nframes_t startf, 
274                                        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 (nframes_t where)
289 {
290         string markername;
291         if (session) {
292                 session->locations()->next_available_name(markername,"mark");
293                 Location *location = new Location (where, where, markername, Location::IsMark);
294                 session->begin_reversible_command (_("add marker"));
295                 XMLNode &before = session->locations()->get_state();
296                 session->locations()->add (location, true);
297                 XMLNode &after = session->locations()->get_state();
298                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
299                 session->commit_reversible_command ();
300         }
301 }
302
303 void
304 Editor::remove_marker (ArdourCanvas::Item& item, GdkEvent* event)
305 {
306         Marker* marker;
307         bool is_start;
308
309         if ((marker = static_cast<Marker*> (item.get_data ("marker"))) == 0) {
310                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
311                 /*NOTREACHED*/
312         }
313
314         Location* loc = find_location_from_marker (marker, is_start);
315
316         if (session && loc) {
317                 Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::really_remove_marker), loc));
318         }
319 }
320
321 gint
322 Editor::really_remove_marker (Location* loc)
323 {
324         session->begin_reversible_command (_("remove marker"));
325         XMLNode &before = session->locations()->get_state();
326         session->locations()->remove (loc);
327         XMLNode &after = session->locations()->get_state();
328         session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
329         session->commit_reversible_command ();
330         return FALSE;
331 }
332
333 void
334 Editor::location_gone (Location *location)
335 {
336         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::location_gone), location));
337         
338         LocationMarkerMap::iterator i;
339
340         if (location == transport_loop_location()) {
341                 update_loop_range_view (true);
342         }
343
344         if (location == transport_punch_location()) {
345                 update_punch_range_view (true);
346         }
347         
348         for (i = location_markers.begin(); i != location_markers.end(); ++i) {
349                 if ((*i).first == location) {
350                         delete (*i).second;
351                         location_markers.erase (i);
352                         break;
353                 }
354         }
355 }
356
357 void
358 Editor::tm_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
359 {
360         if (tm_marker_menu == 0) {
361                 build_tm_marker_menu ();
362         }
363
364         marker_menu_item = item;
365         tm_marker_menu->popup (1, ev->time);
366
367 }
368
369 void
370 Editor::marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
371 {
372         Marker * marker;
373         if ((marker = reinterpret_cast<Marker *> (item->get_data("marker"))) == 0) {
374                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
375                 /*NOTREACHED*/
376         }
377         
378         bool is_start;
379         Location * loc = find_location_from_marker (marker, is_start);
380         if (loc == transport_loop_location() || loc == transport_punch_location()) {
381                 if (transport_marker_menu == 0) {
382                         build_range_marker_menu (true);
383                 }
384                 marker_menu_item = item;
385                 transport_marker_menu->popup (1, ev->time);
386         } else {
387
388                 if (loc->is_mark()) {
389                         bool start_or_end = loc->is_start() || loc->is_end();
390                         Menu *markerMenu;
391                         if (start_or_end) {
392                                 if (start_end_marker_menu == 0)
393                                         build_marker_menu (true);
394                                 markerMenu = start_end_marker_menu;
395                         } else {
396                                 if (marker_menu == 0)
397                                         build_marker_menu (false);
398                                 markerMenu = marker_menu;
399                         }
400
401
402                 // GTK2FIX use action group sensitivity
403 #ifdef GTK2FIX
404                 if (children.size() >= 3) {
405                         MenuItem * loopitem = &children[2];
406                         if (loopitem) {
407                                 if (loc->is_mark()) {
408                                         loopitem->set_sensitive(false);
409                                 }
410                                 else {
411                                         loopitem->set_sensitive(true);
412                                 }
413                         }
414                 }
415 #endif          
416                 marker_menu_item = item;
417                 markerMenu->popup (1, ev->time);
418                 }
419
420                 if (loc->is_range_marker()) {
421                        if (range_marker_menu == 0){
422                               build_range_marker_menu (false);
423                        }
424                        marker_menu_item = item;
425                        range_marker_menu->popup (1, ev->time);
426                 }
427         }
428 }
429
430 void
431 Editor::new_transport_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
432 {
433         if (new_transport_marker_menu == 0) {
434                 build_new_transport_marker_menu ();
435         }
436
437         new_transport_marker_menu->popup (1, ev->time);
438
439 }
440
441 void
442 Editor::transport_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
443 {
444         if (transport_marker_menu == 0) {
445                 build_range_marker_menu (true);
446         }
447
448         transport_marker_menu->popup (1, ev->time);
449 }
450
451 void
452 Editor::build_marker_menu (bool start_or_end)
453 {
454         using namespace Menu_Helpers;
455
456         Menu *markerMenu = new Menu;
457         if (start_or_end) {
458                 start_end_marker_menu = markerMenu;
459         } else {
460                 marker_menu = markerMenu;
461         }
462         MenuList& items = markerMenu->items();
463         markerMenu->set_name ("ArdourContextMenu");
464
465         items.push_back (MenuElem (_("Locate to Mark"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
466         items.push_back (MenuElem (_("Play from Mark"), mem_fun(*this, &Editor::marker_menu_play_from)));
467         items.push_back (MenuElem (_("Set Mark from Playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
468
469         items.push_back (SeparatorElem());
470
471         items.push_back (MenuElem (_("Hide Mark"), mem_fun(*this, &Editor::marker_menu_hide)));
472         if (start_or_end) return;
473         items.push_back (MenuElem (_("Rename Mark"), mem_fun(*this, &Editor::marker_menu_rename)));
474         items.push_back (MenuElem (_("Remove Mark"), mem_fun(*this, &Editor::marker_menu_remove)));
475
476 }
477
478 void
479 Editor::build_range_marker_menu (bool loop_or_punch)
480 {
481         using namespace Menu_Helpers;
482
483         Menu *markerMenu = new Menu;
484         if (loop_or_punch) {
485                 transport_marker_menu = markerMenu;
486         } else {
487                 range_marker_menu = markerMenu;
488         }
489         MenuList& items = markerMenu->items();
490         markerMenu->set_name ("ArdourContextMenu");
491
492         items.push_back (MenuElem (_("Locate to Range Mark"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
493         items.push_back (MenuElem (_("Play from Range Mark"), mem_fun(*this, &Editor::marker_menu_play_from)));
494         if (! loop_or_punch) {
495                 items.push_back (MenuElem (_("Play Range"), mem_fun(*this, &Editor::marker_menu_play_range)));
496                 items.push_back (MenuElem (_("Loop Range"), mem_fun(*this, &Editor::marker_menu_loop_range)));
497         }
498         items.push_back (MenuElem (_("Set Range Mark from Playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
499         items.push_back (MenuElem (_("Set Range from Range Selection"), mem_fun(*this, &Editor::marker_menu_set_from_selection)));
500
501         items.push_back (SeparatorElem());
502
503         items.push_back (MenuElem (_("Hide Range"), mem_fun(*this, &Editor::marker_menu_hide)));
504         if (! loop_or_punch) {
505                 items.push_back (MenuElem (_("Rename Range"), mem_fun(*this, &Editor::marker_menu_rename)));
506                 items.push_back (MenuElem (_("Remove Range"), mem_fun(*this, &Editor::marker_menu_remove)));
507         }
508
509         items.push_back (SeparatorElem());
510
511         items.push_back (MenuElem (_("Separate Regions in Range"), mem_fun(*this, &Editor::marker_menu_separate_regions_using_location)));
512         items.push_back (MenuElem (_("Select All in Range"), mem_fun(*this, &Editor::marker_menu_select_all_selectables_using_range)));
513         items.push_back (MenuElem (_("Select Range"), mem_fun(*this, &Editor::marker_menu_select_using_range)));
514
515 }
516
517 void
518 Editor::build_tm_marker_menu ()
519 {
520         using namespace Menu_Helpers;
521
522         tm_marker_menu = new Menu;
523         MenuList& items = tm_marker_menu->items();
524         tm_marker_menu->set_name ("ArdourContextMenu");
525
526         items.push_back (MenuElem (_("Edit"), mem_fun(*this, &Editor::marker_menu_edit)));
527         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::marker_menu_remove)));
528 }
529
530 void
531 Editor::build_new_transport_marker_menu ()
532 {
533         using namespace Menu_Helpers;
534
535         new_transport_marker_menu = new Menu;
536         MenuList& items = new_transport_marker_menu->items();
537         new_transport_marker_menu->set_name ("ArdourContextMenu");
538
539         items.push_back (MenuElem (_("Set Loop Range"), mem_fun(*this, &Editor::new_transport_marker_menu_set_loop)));
540         items.push_back (MenuElem (_("Set Punch Range"), mem_fun(*this, &Editor::new_transport_marker_menu_set_punch)));
541
542         new_transport_marker_menu->signal_unmap_event().connect ( mem_fun(*this, &Editor::new_transport_marker_menu_popdown)); 
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_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                 set_selection_from_range (*l);
578         }
579 }
580
581 void
582 Editor::marker_menu_select_all_selectables_using_range ()
583 {
584         Marker* marker;
585
586         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
587                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
588                 /*NOTREACHED*/
589         }
590
591         Location* l;
592         bool is_start;
593
594         if (((l = find_location_from_marker (marker, is_start)) != 0) && (l->end() > l->start())) {
595                 select_all_within (l->start(), l->end() - 1, 0,  DBL_MAX, Selection::Set);
596         }
597           
598 }
599
600 void
601 Editor::marker_menu_separate_regions_using_location ()
602 {
603         Marker* marker;
604
605         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
606                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
607                 /*NOTREACHED*/
608         }
609
610         Location* l;
611         bool is_start;
612
613         if (((l = find_location_from_marker (marker, is_start)) != 0) && (l->end() > l->start())) {
614                 separate_regions_using_location (*l);
615         }
616           
617 }
618
619 void
620 Editor::marker_menu_play_from ()
621 {
622         Marker* marker;
623
624         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
625                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
626                 /*NOTREACHED*/
627         }
628
629         Location* l;
630         bool is_start;
631         
632         if ((l = find_location_from_marker (marker, is_start)) != 0) {
633
634                 if (l->is_mark()) {
635                         session->request_locate (l->start(), true);
636                 }
637                 else {
638                         //session->request_bounded_roll (l->start(), l->end());
639                         
640                         if (is_start) {
641                                 session->request_locate (l->start(), true);
642                         } else {
643                                 session->request_locate (l->end(), true);
644                         }
645                 }
646         }
647 }
648
649 void
650 Editor::marker_menu_set_playhead ()
651 {
652         Marker* marker;
653
654         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
655                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
656                 /*NOTREACHED*/
657         }
658
659         Location* l;
660         bool is_start;
661         
662         if ((l = find_location_from_marker (marker, is_start)) != 0) {
663
664                 if (l->is_mark()) {
665                         session->request_locate (l->start(), false);
666                 }
667                 else {
668                         if (is_start) {
669                                 session->request_locate (l->start(), false);
670                         } else {
671                                 session->request_locate (l->end(), false);
672                         }
673                 }
674         }
675 }
676
677 void
678 Editor::marker_menu_set_from_playhead ()
679 {
680         Marker* marker;
681
682         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
683                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
684                 /*NOTREACHED*/
685         }
686
687         Location* l;
688         bool is_start;
689         
690         if ((l = find_location_from_marker (marker, is_start)) != 0) {
691
692                 if (l->is_mark()) {
693                         l->set_start (session->transport_frame ());
694                 }
695                 else {
696                         if (is_start) {
697                                 l->set_start (session->transport_frame ());
698                         } else {
699                                 l->set_end (session->transport_frame ());
700                         }
701                 }
702         }
703 }
704
705 void
706 Editor::marker_menu_set_from_selection ()
707 {
708         Marker* marker;
709
710         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
711                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
712                 /*NOTREACHED*/
713         }
714
715         Location* l;
716         bool is_start;
717         
718         if ((l = find_location_from_marker (marker, is_start)) != 0) {
719
720                 if (l->is_mark()) {
721                         // nothing for now
722                 }
723                 else {
724
725                         /* if range selection use first to last */
726
727                         if (mouse_mode == Editing::MouseRange) {
728                                 if (!selection->time.empty()) {
729                                         l->set_start (selection->time.start());
730                                         l->set_end (selection->time.end_frame());
731                                 }
732                         }
733                         else {
734                                 if (!selection->regions.empty()) {
735                                         l->set_start (selection->regions.start());
736                                         l->set_end (selection->regions.end_frame());
737                                 }
738                         }
739                 }
740         }
741 }
742
743
744 void
745 Editor::marker_menu_play_range ()
746 {
747         Marker* marker;
748
749         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
750                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
751                 /*NOTREACHED*/
752         }
753
754         Location* l;
755         bool is_start;
756         
757         if ((l = find_location_from_marker (marker, is_start)) != 0) {
758
759                 if (l->is_mark()) {
760                         session->request_locate (l->start(), true);
761                 }
762                 else {
763                         session->request_bounded_roll (l->start(), l->end());
764                         
765                 }
766         }
767 }
768
769 void
770 Editor::marker_menu_loop_range ()
771 {
772         Marker* marker;
773
774         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
775                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
776                 /*NOTREACHED*/
777         }
778
779         Location* l;
780         bool is_start;
781         
782         if ((l = find_location_from_marker (marker, is_start)) != 0) {
783                 Location* l2;
784                 if ((l2 = transport_loop_location()) != 0) {
785                         l2->set (l->start(), l->end());
786                         
787                         // enable looping, reposition and start rolling
788                         session->request_play_loop(true);
789                         session->request_locate (l2->start(), true);
790                 }
791         }
792 }
793
794 void
795 Editor::marker_menu_edit ()
796 {
797         MeterMarker* mm;
798         TempoMarker* tm;
799         Marker* marker;
800
801         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
802                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
803                 /*NOTREACHED*/
804         }
805
806         if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
807                 edit_meter_section (&mm->meter());
808         } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
809                 edit_tempo_section (&tm->tempo());
810         } else {
811                 fatal << X_("programming erorr: unhandled marker type in Editor::marker_menu_edit")
812                       << endmsg;
813                 /*NOTREACHED*/
814         }
815 }
816
817 void
818 Editor::marker_menu_remove ()
819 {
820         MeterMarker* mm;
821         TempoMarker* tm;
822         Marker* marker;
823
824         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
825                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
826                 /*NOTREACHED*/
827         }
828
829         if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
830                 remove_meter_marker (marker_menu_item);
831         } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
832                 remove_tempo_marker (marker_menu_item);
833         } else {
834                 remove_marker (*marker_menu_item, (GdkEvent*) 0);
835         }
836 }
837
838 void
839 Editor::marker_menu_rename ()
840 {
841         Marker* marker;
842
843         if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
844                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
845                 /*NOTREACHED*/
846         }
847
848         Location* loc;
849         bool is_start;
850
851         loc = find_location_from_marker (marker, is_start);
852
853         if (!loc) return;
854         
855         ArdourPrompter dialog (true);
856         string txt;
857
858         dialog.set_prompt (_("New Name:"));
859         
860         if (loc->is_mark()) {
861                 dialog.set_title (_("ardour: rename mark"));
862         } else {
863                 dialog.set_title (_("ardour: rename range"));
864         }
865
866         dialog.set_name ("MarkRenameWindow");
867         dialog.set_size_request (250, -1);
868         dialog.set_position (Gtk::WIN_POS_MOUSE);
869
870         dialog.add_button (_("Rename"), RESPONSE_ACCEPT);
871         dialog.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
872         dialog.set_initial_text (loc->name());
873
874         dialog.show ();
875
876         switch (dialog.run ()) {
877         case RESPONSE_ACCEPT:
878                 break;
879         default:
880                 return;
881         }
882
883         begin_reversible_command ( _("rename marker") );
884         XMLNode &before = session->locations()->get_state();
885
886         dialog.get_result(txt);
887         loc->set_name (txt);
888         
889         XMLNode &after = session->locations()->get_state();
890         session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
891         commit_reversible_command ();
892 }
893
894 gint
895 Editor::new_transport_marker_menu_popdown (GdkEventAny *ev)
896 {
897         // hide rects
898         transport_bar_drag_rect->hide();
899         range_marker_drag_rect->hide();
900
901         return FALSE;
902 }
903
904 void
905 Editor::new_transport_marker_menu_set_loop ()
906 {
907         if (!session) return;
908         
909         begin_reversible_command (_("set loop range"));
910         
911         Location* tll;
912
913         if ((tll = transport_loop_location()) == 0) {
914                 Location* loc = new Location (temp_location->start(), temp_location->end(), _("Loop"),  Location::IsAutoLoop);
915                 XMLNode &before = session->locations()->get_state();
916                 session->locations()->add (loc, true);
917                 session->set_auto_loop_location (loc);
918                 XMLNode &after = session->locations()->get_state();
919                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
920         }
921         else {
922                 XMLNode &before = tll->get_state();
923                 tll->set_hidden (false, this);
924                 tll->set (temp_location->start(), temp_location->end());
925                 XMLNode &after = tll->get_state();
926                 session->add_command (new MementoCommand<Location>(*tll, &before, &after));
927         }
928         
929         commit_reversible_command ();
930 }
931
932 void
933 Editor::new_transport_marker_menu_set_punch ()
934 {
935         if (!session) return;
936         
937         begin_reversible_command (_("set punch range"));
938         
939         Location* tpl;
940
941         if ((tpl = transport_punch_location()) == 0) {
942                 tpl = new Location (temp_location->start(), temp_location->end(), _("Punch"), Location::IsAutoPunch);
943                 XMLNode &before = session->locations()->get_state();
944                 session->locations()->add (tpl, true);
945                 session->set_auto_punch_location (tpl);
946                 XMLNode &after = session->locations()->get_state();
947                 session->add_command (new MementoCommand<Locations>(*(session->locations()), &before, &after));
948         } else {
949                 XMLNode &before = tpl->get_state();
950                 tpl->set_hidden(false, this);
951                 tpl->set(temp_location->start(), temp_location->end());
952                 XMLNode &after = tpl->get_state();
953                 session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
954         }
955         
956         commit_reversible_command ();
957 }
958
959 void
960 Editor::update_loop_range_view (bool visibility)
961 {
962         if (session == 0) {
963                 return;
964         }
965
966         Location* tll;
967
968         if (session->get_play_loop() && ((tll = transport_loop_location()) != 0)) {
969
970                 double x1 = frame_to_pixel (tll->start());
971                 double x2 = frame_to_pixel (tll->end());
972                 
973                 transport_loop_range_rect->property_x1() = x1;
974                 transport_loop_range_rect->property_x2() = x2;
975                 
976                 if (visibility) {
977                         transport_loop_range_rect->show();
978                 }
979         }
980         else if (visibility) {
981                 transport_loop_range_rect->hide();
982         }
983 }
984
985 void
986 Editor::update_punch_range_view (bool visibility)
987 {
988         if (session == 0) {
989                 return;
990         }
991
992         Location* tpl;
993
994         if ((Config->get_punch_in() || Config->get_punch_out()) && ((tpl = transport_punch_location()) != 0)) {
995
996                 double x1 = frame_to_pixel (tpl->start());
997                 double x2 = frame_to_pixel (tpl->end());
998                 
999                 transport_punch_range_rect->property_x1() = x1;
1000                 transport_punch_range_rect->property_x2() = x2;
1001                 
1002                 if (visibility) {
1003                         transport_punch_range_rect->show();
1004                 }
1005         }
1006         else if (visibility) {
1007                 transport_punch_range_rect->hide();
1008         }
1009
1010 //      if (session->get_punch_in()) {
1011 //              double x = frame_to_pixel (transport_punch_location->start());
1012 //              gnome_canvas_item_set (transport_punchin_line, "x1", x, "x2", x, NULL);
1013                 
1014 //              if (visibility) {
1015 //                      gnome_canvas_item_show (transport_punchin_line);
1016 //              }
1017 //      }
1018 //      else if (visibility) {
1019 //              gnome_canvas_item_hide (transport_punchin_line);
1020 //      }
1021         
1022 //      if (session->get_punch_out()) {
1023 //              double x = frame_to_pixel (transport_punch_location->end());
1024                 
1025 //              gnome_canvas_item_set (transport_punchout_line, "x1", x, "x2", x, NULL);
1026                 
1027 //              if (visibility) {
1028 //                      gnome_canvas_item_show (transport_punchout_line);
1029 //              }
1030 //      }
1031 //      else if (visibility) {
1032 //              gnome_canvas_item_hide (transport_punchout_line);
1033 //      }
1034 }