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