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