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