2 Copyright (C) 2000 Paul Davis
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.
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.
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.
21 #include <sigc++/rettype.h>
25 #include <libgnomecanvas/libgnomecanvas.h>
26 #include <gtkmm2ext/gtk_ui.h>
28 #include <ardour/location.h>
32 #include "selection.h"
34 #include "gui_thread.h"
40 using namespace ARDOUR;
44 Editor::clear_marker_display ()
46 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
50 location_markers.clear ();
54 Editor::add_new_location (Location *location)
56 LocationMarkers *lam = new LocationMarkers;
59 if (location->is_cd_marker()) {
60 color = location_cd_marker_color;
61 } else if (location->is_mark()) {
62 color = location_marker_color;
63 } else if (location->is_auto_loop()) {
64 color = location_loop_color;
65 } else if (location->is_auto_punch()) {
66 color = location_punch_color;
68 color = location_range_color;
71 if (location->is_mark()) {
72 lam->start = new Marker (*this, GNOME_CANVAS_GROUP(marker_group), color,
73 location->name(), Marker::Mark, PublicEditor::canvas_marker_event, location->start());
76 } else if (location->is_auto_loop()) {
78 lam->start = new Marker (*this, GNOME_CANVAS_GROUP(transport_marker_group), color,
79 location->name(), Marker::LoopStart, PublicEditor::canvas_marker_event, location->start());
80 lam->end = new Marker (*this, GNOME_CANVAS_GROUP(transport_marker_group), color,
81 location->name(), Marker::LoopEnd, PublicEditor::canvas_marker_event, location->end());
83 } else if (location->is_auto_punch()) {
85 lam->start = new Marker (*this, GNOME_CANVAS_GROUP(transport_marker_group), color,
86 location->name(), Marker::PunchIn, PublicEditor::canvas_marker_event, location->start());
87 lam->end = new Marker (*this, GNOME_CANVAS_GROUP(transport_marker_group), color,
88 location->name(), Marker::PunchOut, PublicEditor::canvas_marker_event, location->end());
93 lam->start = new Marker (*this, GNOME_CANVAS_GROUP(range_marker_group), color,
94 location->name(), Marker::Start, PublicEditor::canvas_marker_event, location->start());
95 lam->end = new Marker (*this, GNOME_CANVAS_GROUP(range_marker_group), color,
96 location->name(), Marker::End, PublicEditor::canvas_marker_event, location->end());
99 if (location->is_hidden ()) {
105 location->start_changed.connect (mem_fun(*this, &Editor::location_changed));
106 location->end_changed.connect (mem_fun(*this, &Editor::location_changed));
107 location->changed.connect (mem_fun(*this, &Editor::location_changed));
108 location->name_changed.connect (mem_fun(*this, &Editor::location_changed));
109 location->FlagsChanged.connect (mem_fun(*this, &Editor::location_flags_changed));
111 pair<Location*,LocationMarkers*> newpair;
113 newpair.first = location;
114 newpair.second = lam;
116 location_markers.insert (newpair);
120 Editor::location_changed (Location *location)
122 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::location_changed), location));
124 LocationMarkers *lam = find_location_markers (location);
127 /* a location that isn't "marked" with markers */
131 lam->set_name (location->name());
132 lam->set_position (location->start(), location->end());
134 if (location->is_auto_loop()) {
135 update_loop_range_view ();
136 } else if (location->is_auto_punch()) {
137 update_punch_range_view ();
142 Editor::location_flags_changed (Location *location, void *src)
144 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::location_flags_changed), location, src));
146 LocationMarkers *lam = find_location_markers (location);
149 /* a location that isn't "marked" with markers */
153 if (location->is_cd_marker()) {
154 lam->set_color_rgba (location_cd_marker_color);
155 } else if (location->is_mark()) {
156 lam->set_color_rgba (location_marker_color);
157 } else if (location->is_auto_punch()) {
158 lam->set_color_rgba (location_punch_color);
159 } else if (location->is_auto_loop()) {
160 lam->set_color_rgba (location_loop_color);
162 lam->set_color_rgba (location_range_color);
165 if (location->is_hidden()) {
172 Editor::LocationMarkers::~LocationMarkers ()
183 Editor::LocationMarkers *
184 Editor::find_location_markers (Location *location)
186 LocationMarkerMap::iterator i;
188 for (i = location_markers.begin(); i != location_markers.end(); ++i) {
189 if ((*i).first == location) {
198 Editor::find_location_from_marker (Marker *marker, bool& is_start)
200 LocationMarkerMap::iterator i;
202 for (i = location_markers.begin(); i != location_markers.end(); ++i) {
203 LocationMarkers *lm = (*i).second;
204 if (lm->start == marker) {
207 } else if (lm->end == marker) {
217 Editor::refresh_location_display_internal (Locations::LocationList& locations)
219 clear_marker_display ();
221 for (Locations::LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
222 add_new_location (*i);
227 Editor::refresh_location_display ()
229 ENSURE_GUI_THREAD(mem_fun(*this, &Editor::refresh_location_display));
232 session->locations()->apply (*this, &Editor::refresh_location_display_internal);
237 Editor::refresh_location_display_s (Change ignored)
239 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::refresh_location_display_s), ignored));
242 session->locations()->apply (*this, &Editor::refresh_location_display_internal);
247 Editor::LocationMarkers::hide()
250 if (end) { end->hide(); }
254 Editor::LocationMarkers::show()
257 if (end) { end->show(); }
261 Editor::LocationMarkers::set_name (const string& str)
263 start->set_name (str);
264 if (end) { end->set_name (str); }
268 Editor::LocationMarkers::set_position (jack_nframes_t startf,
271 start->set_position (startf);
272 if (end) { end->set_position (endf); }
276 Editor::LocationMarkers::set_color_rgba (uint32_t rgba)
278 start->set_color_rgba (rgba);
279 if (end) { end->set_color_rgba (rgba); }
283 Editor::mouse_add_new_marker (jack_nframes_t where)
286 Location *location = new Location (where, where, "mark", Location::IsMark);
287 session->begin_reversible_command (_("add marker"));
288 session->add_undo (session->locations()->get_memento());
289 session->locations()->add (location, true);
290 session->add_redo_no_execute (session->locations()->get_memento());
291 session->commit_reversible_command ();
296 Editor::remove_marker (GnomeCanvasItem* item, GdkEvent* event)
301 if ((marker = static_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
302 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
306 Location* loc = find_location_from_marker (marker, is_start);
308 if (session && loc) {
310 /* you can't hide or delete this marker */
313 if (loc->is_auto_loop() || loc->is_auto_punch()) {
315 loc->set_hidden (true, this);
318 Gtk::Main::idle.connect (bind (mem_fun(*this, &Editor::really_remove_marker), loc));
324 Editor::really_remove_marker (Location* loc)
326 session->begin_reversible_command (_("remove marker"));
327 session->add_undo (session->locations()->get_memento());
328 session->locations()->remove (loc);
329 session->add_redo_no_execute (session->locations()->get_memento());
330 session->commit_reversible_command ();
335 Editor::location_gone (Location *location)
337 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::location_gone), location));
339 LocationMarkerMap::iterator i;
341 if (location == transport_loop_location()) {
342 update_loop_range_view (true);
345 if (location == transport_punch_location()) {
346 update_punch_range_view (true);
349 for (i = location_markers.begin(); i != location_markers.end(); ++i) {
350 if ((*i).first == location) {
352 location_markers.erase (i);
359 Editor::tm_marker_context_menu (GdkEventButton* ev, GnomeCanvasItem* item)
361 if (tm_marker_menu == 0) {
362 build_tm_marker_menu ();
365 marker_menu_item = item;
366 tm_marker_menu->popup (1, ev->time);
372 Editor::marker_context_menu (GdkEventButton* ev, GnomeCanvasItem* item)
375 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(item), "marker"))) == 0) {
376 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
381 Location * loc = find_location_from_marker (marker, is_start);
382 if (loc == transport_loop_location() || loc == transport_punch_location()) {
383 if (transport_marker_menu == 0) {
384 build_transport_marker_menu ();
386 marker_menu_item = item;
387 transport_marker_menu->popup (1, ev->time);
390 if (marker_menu == 0) {
391 build_marker_menu ();
394 Menu_Helpers::MenuList & children = marker_menu->items();
395 // XXX: should really find this some other way
396 if (children.size() >= 3) {
397 MenuItem * loopitem = children[2];
399 if (loc->is_mark()) {
400 loopitem->set_sensitive(false);
403 loopitem->set_sensitive(true);
408 marker_menu_item = item;
409 marker_menu->popup (1, ev->time);
415 Editor::new_transport_marker_context_menu (GdkEventButton* ev, GnomeCanvasItem* item)
417 if (new_transport_marker_menu == 0) {
418 build_new_transport_marker_menu ();
421 new_transport_marker_menu->popup (1, ev->time);
426 Editor::transport_marker_context_menu (GdkEventButton* ev, GnomeCanvasItem* item)
428 if (transport_marker_menu == 0) {
429 build_transport_marker_menu ();
432 transport_marker_menu->popup (1, ev->time);
436 Editor::build_marker_menu ()
438 using namespace Menu_Helpers;
440 marker_menu = new Menu;
441 MenuList& items = marker_menu->items();
442 marker_menu->set_name ("ArdourContextMenu");
444 items.push_back (MenuElem (_("Locate to"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
445 items.push_back (MenuElem (_("Play from"), mem_fun(*this, &Editor::marker_menu_play_from)));
446 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::marker_menu_loop_range)));
447 items.push_back (MenuElem (_("Set from playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
448 items.push_back (MenuElem (_("Set from range"), mem_fun(*this, &Editor::marker_menu_set_from_selection)));
450 items.push_back (SeparatorElem());
452 items.push_back (MenuElem (_("Rename"), mem_fun(*this, &Editor::marker_menu_rename)));
453 items.push_back (MenuElem (_("Hide"), mem_fun(*this, &Editor::marker_menu_hide)));
454 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::marker_menu_remove)));
458 Editor::build_tm_marker_menu ()
460 using namespace Menu_Helpers;
462 tm_marker_menu = new Menu;
463 MenuList& items = tm_marker_menu->items();
464 tm_marker_menu->set_name ("ArdourContextMenu");
466 items.push_back (MenuElem (_("Edit"), mem_fun(*this, &Editor::marker_menu_edit)));
467 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::marker_menu_remove)));
471 Editor::build_new_transport_marker_menu ()
473 using namespace Menu_Helpers;
475 new_transport_marker_menu = new Menu;
476 MenuList& items = new_transport_marker_menu->items();
477 new_transport_marker_menu->set_name ("ArdourContextMenu");
479 items.push_back (MenuElem (_("Set Loop Range"), mem_fun(*this, &Editor::new_transport_marker_menu_set_loop)));
480 items.push_back (MenuElem (_("Set Punch Range"), mem_fun(*this, &Editor::new_transport_marker_menu_set_punch)));
482 new_transport_marker_menu->signal_unmap_event.connect ( mem_fun(*this, &Editor::new_transport_marker_menu_popdown));
486 Editor::build_transport_marker_menu ()
488 using namespace Menu_Helpers;
490 transport_marker_menu = new Menu;
491 MenuList& items = transport_marker_menu->items();
492 transport_marker_menu->set_name ("ArdourContextMenu");
494 items.push_back (MenuElem (_("Locate to"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
495 items.push_back (MenuElem (_("Play from"), mem_fun(*this, &Editor::marker_menu_play_from)));
496 items.push_back (MenuElem (_("Set from playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
497 items.push_back (MenuElem (_("Set from range"), mem_fun(*this, &Editor::marker_menu_set_from_selection)));
498 items.push_back (SeparatorElem());
499 items.push_back (MenuElem (_("Hide"), mem_fun(*this, &Editor::marker_menu_hide)));
503 Editor::marker_menu_hide ()
507 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
508 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
515 if ((l = find_location_from_marker (marker, is_start)) != 0) {
516 l->set_hidden (true, this);
521 Editor::marker_menu_play_from ()
525 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
526 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
533 if ((l = find_location_from_marker (marker, is_start)) != 0) {
536 session->request_locate (l->start(), true);
539 //session->request_bounded_roll (l->start(), l->end());
542 session->request_locate (l->start(), true);
544 session->request_locate (l->end(), true);
551 Editor::marker_menu_set_playhead ()
555 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
556 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
563 if ((l = find_location_from_marker (marker, is_start)) != 0) {
566 session->request_locate (l->start(), false);
570 session->request_locate (l->start(), false);
572 session->request_locate (l->end(), false);
579 Editor::marker_menu_set_from_playhead ()
583 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
584 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
591 if ((l = find_location_from_marker (marker, is_start)) != 0) {
594 l->set_start (session->transport_frame ());
598 l->set_start (session->transport_frame ());
600 l->set_end (session->transport_frame ());
607 Editor::marker_menu_set_from_selection ()
611 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
612 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
619 if ((l = find_location_from_marker (marker, is_start)) != 0) {
626 /* if range selection use first to last */
628 if (mouse_mode == Editing::MouseRange) {
629 if (!selection->time.empty()) {
630 l->set_start (selection->time.start());
631 l->set_end (selection->time.end_frame());
635 if (!selection->audio_regions.empty()) {
636 l->set_start (selection->audio_regions.start());
637 l->set_end (selection->audio_regions.end_frame());
645 Editor::marker_menu_loop_range ()
649 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
650 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
657 if ((l = find_location_from_marker (marker, is_start)) != 0) {
659 if ((l2 = transport_loop_location()) != 0) {
660 l2->set (l->start(), l->end());
662 // enable looping, reposition and start rolling
663 session->request_auto_loop(true);
664 session->request_locate (l2->start(), true);
670 Editor::marker_menu_edit ()
676 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
677 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
681 if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
682 edit_meter_section (&mm->meter());
683 } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
684 edit_tempo_section (&tm->tempo());
686 fatal << X_("programming erorr: unhandled marker type in Editor::marker_menu_edit")
693 Editor::marker_menu_remove ()
699 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
700 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
704 if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
705 remove_meter_marker (marker_menu_item);
706 } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
707 remove_tempo_marker (marker_menu_item);
709 remove_marker (marker_menu_item, (GdkEvent*) 0);
714 Editor::marker_menu_rename ()
718 if ((marker = reinterpret_cast<Marker *> (gtk_object_get_data (GTK_OBJECT(marker_menu_item), "marker"))) == 0) {
719 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
726 loc = find_location_from_marker (marker, is_start);
732 Button ok_button (_("OK"));
733 Button cancel_button (_("Cancel"));
735 if (loc->is_mark()) {
736 dialog.set_title (_("ardour: rename mark"));
738 dialog.set_title (_("ardour: rename range"));
741 dialog.set_name ("MarkRenameWindow");
742 dialog.set_size_request (300, -1);
743 dialog.set_position (Gtk::WIN_POS_MOUSE);
744 dialog.set_modal (true);
746 dialog.get_vbox()->set_border_width (10);
747 dialog.get_vbox()->pack_start (entry);
748 dialog.get_action_area()->pack_start (ok_button);
749 dialog.get_action_area()->pack_start (cancel_button);
751 entry.set_text (loc->name());
752 entry.set_name ("MarkerNameDisplay");
753 ok_button.set_name ("EditorGTKButton");
754 cancel_button.set_name ("EditorGTKButton");
756 entry.activate.connect (bind (mem_fun(*this, &Editor::finish_sub_event_loop), 1));
757 cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::finish_sub_event_loop), -1));
758 ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::finish_sub_event_loop), 1));
759 dialog.signal_delete_event.connect (bind (mem_fun(*this, &Editor::finish_sub_event_loop_on_delete), -1));
764 run_sub_event_loop ();
766 if (sub_event_loop_status == 1) {
771 if ((l = find_location_from_marker (marker, is_start)) != 0) {
772 l->set_name (entry.get_text());
778 Editor::new_transport_marker_menu_popdown (GdkEventAny *ev)
781 gnome_canvas_item_hide (transport_bar_drag_rect);
782 gnome_canvas_item_hide (range_marker_drag_rect);
788 Editor::new_transport_marker_menu_set_loop ()
790 if (!session) return;
792 begin_reversible_command (_("set loop range"));
796 if ((tll = transport_loop_location()) == 0) {
797 Location* loc = new Location (temp_location->start(), temp_location->end(), _("Loop"), Location::IsAutoLoop);
798 session->add_undo (session->locations()->get_memento());
799 session->locations()->add (loc, true);
800 session->set_auto_loop_location (loc);
801 session->add_redo_no_execute (session->locations()->get_memento());
804 session->add_undo (rettype<void>(bind (mem_fun (*tll, &Location::set), tll->start(), tll->end())));
805 session->add_redo (rettype<void>(bind (mem_fun (*tll, &Location::set), temp_location->start(), temp_location->end())));
806 tll->set_hidden (false, this);
807 tll->set (temp_location->start(), temp_location->end());
810 commit_reversible_command ();
814 Editor::new_transport_marker_menu_set_punch ()
816 if (!session) return;
818 begin_reversible_command (_("set punch range"));
822 if ((tpl = transport_punch_location()) == 0) {
823 tpl = new Location (temp_location->start(), temp_location->end(), _("Punch"), Location::IsAutoPunch);
824 session->add_undo (session->locations()->get_memento());
825 session->locations()->add (tpl, true);
826 session->set_auto_punch_location (tpl);
827 session->add_redo_no_execute (session->locations()->get_memento());
829 session->add_undo (rettype<void>(bind (mem_fun (*tpl, &Location::set), tpl->start(), tpl->end())));
830 session->add_redo (rettype<void>(bind (mem_fun (*tpl, &Location::set), temp_location->start(), temp_location->end())));
831 tpl->set_hidden(false, this);
832 tpl->set(temp_location->start(), temp_location->end());
835 commit_reversible_command ();
839 Editor::update_loop_range_view (bool visibility)
847 if (session->get_auto_loop() && ((tll = transport_loop_location()) != 0)) {
849 double x1 = frame_to_pixel (tll->start());
850 double x2 = frame_to_pixel (tll->end());
852 gnome_canvas_item_set (transport_loop_range_rect, "x1", x1, "x2", x2, NULL);
855 gnome_canvas_item_show (transport_loop_range_rect);
858 else if (visibility) {
859 gnome_canvas_item_hide (transport_loop_range_rect);
864 Editor::update_punch_range_view (bool visibility)
872 if ((session->get_punch_in() || session->get_punch_out()) && ((tpl = transport_punch_location()) != 0)) {
874 double x1 = frame_to_pixel (tpl->start());
875 double x2 = frame_to_pixel (tpl->end());
877 gnome_canvas_item_set (transport_punch_range_rect, "x1", x1, "x2", x2, NULL);
880 gnome_canvas_item_show (transport_punch_range_rect);
883 else if (visibility) {
884 gnome_canvas_item_hide (transport_punch_range_rect);
887 // if (session->get_punch_in()) {
888 // double x = frame_to_pixel (transport_punch_location->start());
889 // gnome_canvas_item_set (transport_punchin_line, "x1", x, "x2", x, NULL);
892 // gnome_canvas_item_show (transport_punchin_line);
895 // else if (visibility) {
896 // gnome_canvas_item_hide (transport_punchin_line);
899 // if (session->get_punch_out()) {
900 // double x = frame_to_pixel (transport_punch_location->end());
902 // gnome_canvas_item_set (transport_punchout_line, "x1", x, "x2", x, NULL);
905 // gnome_canvas_item_show (transport_punchout_line);
908 // else if (visibility) {
909 // gnome_canvas_item_hide (transport_punchout_line);