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++/retype.h>
25 #include <libgnomecanvas/libgnomecanvas.h>
26 #include <gtkmm2ext/gtk_ui.h>
28 #include <ardour/location.h>
32 #include "selection.h"
33 #include "simplerect.h"
35 #include "gui_thread.h"
36 #include "simplerect.h"
42 using namespace ARDOUR;
46 Editor::clear_marker_display ()
48 for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
52 location_markers.clear ();
56 Editor::add_new_location (Location *location)
58 LocationMarkers *lam = new LocationMarkers;
61 if (location->is_cd_marker()) {
62 color = location_cd_marker_color;
63 } else if (location->is_mark()) {
64 color = location_marker_color;
65 } else if (location->is_auto_loop()) {
66 color = location_loop_color;
67 } else if (location->is_auto_punch()) {
68 color = location_punch_color;
70 color = location_range_color;
73 if (location->is_mark()) {
74 lam->start = new Marker (*this, *marker_group, color, location->name(), Marker::Mark, location->start());
77 } else if (location->is_auto_loop()) {
79 lam->start = new Marker (*this, *transport_marker_group, color,
80 location->name(), Marker::LoopStart, location->start());
81 lam->end = new Marker (*this, *transport_marker_group, color,
82 location->name(), Marker::LoopEnd, location->end());
84 } else if (location->is_auto_punch()) {
86 lam->start = new Marker (*this, *transport_marker_group, color,
87 location->name(), Marker::PunchIn, location->start());
88 lam->end = new Marker (*this, *transport_marker_group, color,
89 location->name(), Marker::PunchOut, location->end());
94 lam->start = new Marker (*this, *range_marker_group, color,
95 location->name(), Marker::Start, location->start());
96 lam->end = new Marker (*this, *range_marker_group, color,
97 location->name(), Marker::End, location->end());
100 if (location->is_hidden ()) {
106 location->start_changed.connect (mem_fun(*this, &Editor::location_changed));
107 location->end_changed.connect (mem_fun(*this, &Editor::location_changed));
108 location->changed.connect (mem_fun(*this, &Editor::location_changed));
109 location->name_changed.connect (mem_fun(*this, &Editor::location_changed));
110 location->FlagsChanged.connect (mem_fun(*this, &Editor::location_flags_changed));
112 pair<Location*,LocationMarkers*> newpair;
114 newpair.first = location;
115 newpair.second = lam;
117 location_markers.insert (newpair);
121 Editor::location_changed (Location *location)
123 ENSURE_GUI_THREAD (bind (mem_fun(*this, &Editor::location_changed), location));
125 LocationMarkers *lam = find_location_markers (location);
128 /* a location that isn't "marked" with markers */
132 lam->set_name (location->name());
133 lam->set_position (location->start(), location->end());
135 if (location->is_auto_loop()) {
136 update_loop_range_view ();
137 } else if (location->is_auto_punch()) {
138 update_punch_range_view ();
143 Editor::location_flags_changed (Location *location, void *src)
145 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::location_flags_changed), location, src));
147 LocationMarkers *lam = find_location_markers (location);
150 /* a location that isn't "marked" with markers */
154 if (location->is_cd_marker()) {
155 lam->set_color_rgba (location_cd_marker_color);
156 } else if (location->is_mark()) {
157 lam->set_color_rgba (location_marker_color);
158 } else if (location->is_auto_punch()) {
159 lam->set_color_rgba (location_punch_color);
160 } else if (location->is_auto_loop()) {
161 lam->set_color_rgba (location_loop_color);
163 lam->set_color_rgba (location_range_color);
166 if (location->is_hidden()) {
173 Editor::LocationMarkers::~LocationMarkers ()
184 Editor::LocationMarkers *
185 Editor::find_location_markers (Location *location)
187 LocationMarkerMap::iterator i;
189 for (i = location_markers.begin(); i != location_markers.end(); ++i) {
190 if ((*i).first == location) {
199 Editor::find_location_from_marker (Marker *marker, bool& is_start)
201 LocationMarkerMap::iterator i;
203 for (i = location_markers.begin(); i != location_markers.end(); ++i) {
204 LocationMarkers *lm = (*i).second;
205 if (lm->start == marker) {
208 } else if (lm->end == marker) {
218 Editor::refresh_location_display_internal (Locations::LocationList& locations)
220 clear_marker_display ();
222 for (Locations::LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
223 add_new_location (*i);
228 Editor::refresh_location_display ()
230 ENSURE_GUI_THREAD(mem_fun(*this, &Editor::refresh_location_display));
233 session->locations()->apply (*this, &Editor::refresh_location_display_internal);
238 Editor::refresh_location_display_s (Change ignored)
240 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::refresh_location_display_s), ignored));
243 session->locations()->apply (*this, &Editor::refresh_location_display_internal);
248 Editor::LocationMarkers::hide()
251 if (end) { end->hide(); }
255 Editor::LocationMarkers::show()
258 if (end) { end->show(); }
262 Editor::LocationMarkers::set_name (const string& str)
264 start->set_name (str);
265 if (end) { end->set_name (str); }
269 Editor::LocationMarkers::set_position (jack_nframes_t startf,
272 start->set_position (startf);
273 if (end) { end->set_position (endf); }
277 Editor::LocationMarkers::set_color_rgba (uint32_t rgba)
279 start->set_color_rgba (rgba);
280 if (end) { end->set_color_rgba (rgba); }
284 Editor::mouse_add_new_marker (jack_nframes_t where)
287 Location *location = new Location (where, where, "mark", Location::IsMark);
288 session->begin_reversible_command (_("add marker"));
289 session->add_undo (session->locations()->get_memento());
290 session->locations()->add (location, true);
291 session->add_redo_no_execute (session->locations()->get_memento());
292 session->commit_reversible_command ();
297 Editor::remove_marker (ArdourCanvas::Item& item, GdkEvent* event)
302 if ((marker = static_cast<Marker*> (item.get_data ("marker"))) == 0) {
303 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
307 Location* loc = find_location_from_marker (marker, is_start);
309 if (session && loc) {
311 /* you can't hide or delete this marker */
314 if (loc->is_auto_loop() || loc->is_auto_punch()) {
316 loc->set_hidden (true, this);
319 Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::really_remove_marker), loc));
325 Editor::really_remove_marker (Location* loc)
327 session->begin_reversible_command (_("remove marker"));
328 session->add_undo (session->locations()->get_memento());
329 session->locations()->remove (loc);
330 session->add_redo_no_execute (session->locations()->get_memento());
331 session->commit_reversible_command ();
336 Editor::location_gone (Location *location)
338 ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::location_gone), location));
340 LocationMarkerMap::iterator i;
342 if (location == transport_loop_location()) {
343 update_loop_range_view (true);
346 if (location == transport_punch_location()) {
347 update_punch_range_view (true);
350 for (i = location_markers.begin(); i != location_markers.end(); ++i) {
351 if ((*i).first == location) {
353 location_markers.erase (i);
360 Editor::tm_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
362 if (tm_marker_menu == 0) {
363 build_tm_marker_menu ();
366 marker_menu_item = item;
367 tm_marker_menu->popup (1, ev->time);
373 Editor::marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
376 if ((marker = reinterpret_cast<Marker *> (item->get_data("marker"))) == 0) {
377 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
382 Location * loc = find_location_from_marker (marker, is_start);
383 if (loc == transport_loop_location() || loc == transport_punch_location()) {
384 if (transport_marker_menu == 0) {
385 build_transport_marker_menu ();
387 marker_menu_item = item;
388 transport_marker_menu->popup (1, ev->time);
391 if (marker_menu == 0) {
392 build_marker_menu ();
395 // GTK2FIX use action group sensitivity
397 if (children.size() >= 3) {
398 MenuItem * loopitem = &children[2];
400 if (loc->is_mark()) {
401 loopitem->set_sensitive(false);
404 loopitem->set_sensitive(true);
409 marker_menu_item = item;
410 marker_menu->popup (1, ev->time);
416 Editor::new_transport_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
418 if (new_transport_marker_menu == 0) {
419 build_new_transport_marker_menu ();
422 new_transport_marker_menu->popup (1, ev->time);
427 Editor::transport_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
429 if (transport_marker_menu == 0) {
430 build_transport_marker_menu ();
433 transport_marker_menu->popup (1, ev->time);
437 Editor::build_marker_menu ()
439 using namespace Menu_Helpers;
441 marker_menu = new Menu;
442 MenuList& items = marker_menu->items();
443 marker_menu->set_name ("ArdourContextMenu");
445 items.push_back (MenuElem (_("Locate to"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
446 items.push_back (MenuElem (_("Play from"), mem_fun(*this, &Editor::marker_menu_play_from)));
447 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::marker_menu_loop_range)));
448 items.push_back (MenuElem (_("Set from playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
449 items.push_back (MenuElem (_("Set from range"), mem_fun(*this, &Editor::marker_menu_set_from_selection)));
451 items.push_back (SeparatorElem());
453 items.push_back (MenuElem (_("Rename"), mem_fun(*this, &Editor::marker_menu_rename)));
454 items.push_back (MenuElem (_("Hide"), mem_fun(*this, &Editor::marker_menu_hide)));
455 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::marker_menu_remove)));
459 Editor::build_tm_marker_menu ()
461 using namespace Menu_Helpers;
463 tm_marker_menu = new Menu;
464 MenuList& items = tm_marker_menu->items();
465 tm_marker_menu->set_name ("ArdourContextMenu");
467 items.push_back (MenuElem (_("Edit"), mem_fun(*this, &Editor::marker_menu_edit)));
468 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::marker_menu_remove)));
472 Editor::build_new_transport_marker_menu ()
474 using namespace Menu_Helpers;
476 new_transport_marker_menu = new Menu;
477 MenuList& items = new_transport_marker_menu->items();
478 new_transport_marker_menu->set_name ("ArdourContextMenu");
480 items.push_back (MenuElem (_("Set Loop Range"), mem_fun(*this, &Editor::new_transport_marker_menu_set_loop)));
481 items.push_back (MenuElem (_("Set Punch Range"), mem_fun(*this, &Editor::new_transport_marker_menu_set_punch)));
483 new_transport_marker_menu->signal_unmap_event().connect ( mem_fun(*this, &Editor::new_transport_marker_menu_popdown));
487 Editor::build_transport_marker_menu ()
489 using namespace Menu_Helpers;
491 transport_marker_menu = new Menu;
492 MenuList& items = transport_marker_menu->items();
493 transport_marker_menu->set_name ("ArdourContextMenu");
495 items.push_back (MenuElem (_("Locate to"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
496 items.push_back (MenuElem (_("Play from"), mem_fun(*this, &Editor::marker_menu_play_from)));
497 items.push_back (MenuElem (_("Set from playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
498 items.push_back (MenuElem (_("Set from range"), mem_fun(*this, &Editor::marker_menu_set_from_selection)));
499 items.push_back (SeparatorElem());
500 items.push_back (MenuElem (_("Hide"), mem_fun(*this, &Editor::marker_menu_hide)));
504 Editor::marker_menu_hide ()
508 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
509 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
516 if ((l = find_location_from_marker (marker, is_start)) != 0) {
517 l->set_hidden (true, this);
522 Editor::marker_menu_play_from ()
526 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
527 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
534 if ((l = find_location_from_marker (marker, is_start)) != 0) {
537 session->request_locate (l->start(), true);
540 //session->request_bounded_roll (l->start(), l->end());
543 session->request_locate (l->start(), true);
545 session->request_locate (l->end(), true);
552 Editor::marker_menu_set_playhead ()
556 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
557 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
564 if ((l = find_location_from_marker (marker, is_start)) != 0) {
567 session->request_locate (l->start(), false);
571 session->request_locate (l->start(), false);
573 session->request_locate (l->end(), false);
580 Editor::marker_menu_set_from_playhead ()
584 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
585 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
592 if ((l = find_location_from_marker (marker, is_start)) != 0) {
595 l->set_start (session->transport_frame ());
599 l->set_start (session->transport_frame ());
601 l->set_end (session->transport_frame ());
608 Editor::marker_menu_set_from_selection ()
612 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
613 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
620 if ((l = find_location_from_marker (marker, is_start)) != 0) {
627 /* if range selection use first to last */
629 if (mouse_mode == Editing::MouseRange) {
630 if (!selection->time.empty()) {
631 l->set_start (selection->time.start());
632 l->set_end (selection->time.end_frame());
636 if (!selection->audio_regions.empty()) {
637 l->set_start (selection->audio_regions.start());
638 l->set_end (selection->audio_regions.end_frame());
646 Editor::marker_menu_loop_range ()
650 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
651 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
658 if ((l = find_location_from_marker (marker, is_start)) != 0) {
660 if ((l2 = transport_loop_location()) != 0) {
661 l2->set (l->start(), l->end());
663 // enable looping, reposition and start rolling
664 session->request_auto_loop(true);
665 session->request_locate (l2->start(), true);
671 Editor::marker_menu_edit ()
677 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
678 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
682 if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
683 edit_meter_section (&mm->meter());
684 } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
685 edit_tempo_section (&tm->tempo());
687 fatal << X_("programming erorr: unhandled marker type in Editor::marker_menu_edit")
694 Editor::marker_menu_remove ()
700 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
701 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
705 if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
706 remove_meter_marker (marker_menu_item);
707 } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
708 remove_tempo_marker (marker_menu_item);
710 remove_marker (*marker_menu_item, (GdkEvent*) 0);
715 Editor::marker_menu_rename ()
719 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
720 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
727 loc = find_location_from_marker (marker, is_start);
734 if (loc->is_mark()) {
735 dialog.set_title (_("ardour: rename mark"));
737 dialog.set_title (_("ardour: rename range"));
740 dialog.set_name ("MarkRenameWindow");
741 dialog.set_size_request (300, -1);
742 dialog.set_position (Gtk::WIN_POS_MOUSE);
743 dialog.set_modal (true);
745 dialog.add_action_widget (entry, RESPONSE_ACCEPT);
746 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
747 dialog.add_button (Stock::CANCEL, RESPONSE_ACCEPT);
749 entry.set_text (loc->name());
750 entry.set_name ("MarkerNameDisplay");
755 switch (dialog.run ()) {
756 case RESPONSE_ACCEPT:
762 loc->set_name (entry.get_text());
766 Editor::new_transport_marker_menu_popdown (GdkEventAny *ev)
769 transport_bar_drag_rect->hide();
770 range_marker_drag_rect->hide();
776 Editor::new_transport_marker_menu_set_loop ()
778 if (!session) return;
780 begin_reversible_command (_("set loop range"));
784 if ((tll = transport_loop_location()) == 0) {
785 Location* loc = new Location (temp_location->start(), temp_location->end(), _("Loop"), Location::IsAutoLoop);
786 session->add_undo (session->locations()->get_memento());
787 session->locations()->add (loc, true);
788 session->set_auto_loop_location (loc);
789 session->add_redo_no_execute (session->locations()->get_memento());
792 session->add_undo (retype_return<void>(bind (mem_fun (*tll, &Location::set), tll->start(), tll->end())));
793 session->add_redo (retype_return<void>(bind (mem_fun (*tll, &Location::set), temp_location->start(), temp_location->end())));
794 tll->set_hidden (false, this);
795 tll->set (temp_location->start(), temp_location->end());
798 commit_reversible_command ();
802 Editor::new_transport_marker_menu_set_punch ()
804 if (!session) return;
806 begin_reversible_command (_("set punch range"));
810 if ((tpl = transport_punch_location()) == 0) {
811 tpl = new Location (temp_location->start(), temp_location->end(), _("Punch"), Location::IsAutoPunch);
812 session->add_undo (session->locations()->get_memento());
813 session->locations()->add (tpl, true);
814 session->set_auto_punch_location (tpl);
815 session->add_redo_no_execute (session->locations()->get_memento());
817 session->add_undo (retype_return<void>(bind (mem_fun (*tpl, &Location::set), tpl->start(), tpl->end())));
818 session->add_redo (retype_return<void>(bind (mem_fun (*tpl, &Location::set), temp_location->start(), temp_location->end())));
819 tpl->set_hidden(false, this);
820 tpl->set(temp_location->start(), temp_location->end());
823 commit_reversible_command ();
827 Editor::update_loop_range_view (bool visibility)
835 if (session->get_auto_loop() && ((tll = transport_loop_location()) != 0)) {
837 double x1 = frame_to_pixel (tll->start());
838 double x2 = frame_to_pixel (tll->end());
840 transport_loop_range_rect->property_x1() = x1;
841 transport_loop_range_rect->property_x2() = x2;
844 transport_loop_range_rect->show();
847 else if (visibility) {
848 transport_loop_range_rect->hide();
853 Editor::update_punch_range_view (bool visibility)
861 if ((session->get_punch_in() || session->get_punch_out()) && ((tpl = transport_punch_location()) != 0)) {
863 double x1 = frame_to_pixel (tpl->start());
864 double x2 = frame_to_pixel (tpl->end());
866 transport_punch_range_rect->property_x1() = x1;
867 transport_punch_range_rect->property_x2() = x2;
870 transport_punch_range_rect->show();
873 else if (visibility) {
874 transport_punch_range_rect->hide();
877 // if (session->get_punch_in()) {
878 // double x = frame_to_pixel (transport_punch_location->start());
879 // gnome_canvas_item_set (transport_punchin_line, "x1", x, "x2", x, NULL);
882 // gnome_canvas_item_show (transport_punchin_line);
885 // else if (visibility) {
886 // gnome_canvas_item_hide (transport_punchin_line);
889 // if (session->get_punch_out()) {
890 // double x = frame_to_pixel (transport_punch_location->end());
892 // gnome_canvas_item_set (transport_punchout_line, "x1", x, "x2", x, NULL);
895 // gnome_canvas_item_show (transport_punchout_line);
898 // else if (visibility) {
899 // gnome_canvas_item_hide (transport_punchout_line);