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);
390 if (marker_menu == 0) {
391 if (loc->is_mark()) {
392 build_marker_menu ();
394 build_range_marker_menu ();
398 // GTK2FIX use action group sensitivity
400 if (children.size() >= 3) {
401 MenuItem * loopitem = &children[2];
403 if (loc->is_mark()) {
404 loopitem->set_sensitive(false);
407 loopitem->set_sensitive(true);
412 marker_menu_item = item;
413 marker_menu->popup (1, ev->time);
419 Editor::new_transport_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
421 if (new_transport_marker_menu == 0) {
422 build_new_transport_marker_menu ();
425 new_transport_marker_menu->popup (1, ev->time);
430 Editor::transport_marker_context_menu (GdkEventButton* ev, ArdourCanvas::Item* item)
432 if (transport_marker_menu == 0) {
433 build_transport_marker_menu ();
436 transport_marker_menu->popup (1, ev->time);
440 Editor::build_marker_menu ()
442 using namespace Menu_Helpers;
444 marker_menu = new Menu;
445 MenuList& items = marker_menu->items();
446 marker_menu->set_name ("ArdourContextMenu");
448 items.push_back (MenuElem (_("Locate to"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
449 items.push_back (MenuElem (_("Play from"), mem_fun(*this, &Editor::marker_menu_play_from)));
450 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::marker_menu_loop_range)));
451 items.push_back (MenuElem (_("Set from playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
452 items.push_back (MenuElem (_("Set from range"), mem_fun(*this, &Editor::marker_menu_set_from_selection)));
454 items.push_back (SeparatorElem());
456 items.push_back (MenuElem (_("Rename"), mem_fun(*this, &Editor::marker_menu_rename)));
457 items.push_back (MenuElem (_("Hide"), mem_fun(*this, &Editor::marker_menu_hide)));
458 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::marker_menu_remove)));
463 Editor::build_range_marker_menu ()
465 using namespace Menu_Helpers;
467 marker_menu = new Menu;
468 MenuList& items = marker_menu->items();
469 marker_menu->set_name ("ArdourContextMenu");
471 items.push_back (MenuElem (_("Locate to"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
472 items.push_back (MenuElem (_("Play from"), mem_fun(*this, &Editor::marker_menu_play_from)));
473 items.push_back (MenuElem (_("Loop range"), mem_fun(*this, &Editor::marker_menu_loop_range)));
474 items.push_back (MenuElem (_("Set from playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
475 items.push_back (MenuElem (_("Set from range"), mem_fun(*this, &Editor::marker_menu_set_from_selection)));
477 items.push_back (SeparatorElem());
479 items.push_back (MenuElem (_("Rename"), mem_fun(*this, &Editor::marker_menu_rename)));
480 items.push_back (MenuElem (_("Hide"), mem_fun(*this, &Editor::marker_menu_hide)));
481 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::marker_menu_remove)));
483 items.push_back (SeparatorElem());
484 items.push_back (MenuElem (_("Select all in Range"), mem_fun(*this, &Editor::marker_menu_select_all_from_range)));
489 Editor::build_tm_marker_menu ()
491 using namespace Menu_Helpers;
493 tm_marker_menu = new Menu;
494 MenuList& items = tm_marker_menu->items();
495 tm_marker_menu->set_name ("ArdourContextMenu");
497 items.push_back (MenuElem (_("Edit"), mem_fun(*this, &Editor::marker_menu_edit)));
498 items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::marker_menu_remove)));
502 Editor::build_new_transport_marker_menu ()
504 using namespace Menu_Helpers;
506 new_transport_marker_menu = new Menu;
507 MenuList& items = new_transport_marker_menu->items();
508 new_transport_marker_menu->set_name ("ArdourContextMenu");
510 items.push_back (MenuElem (_("Set Loop Range"), mem_fun(*this, &Editor::new_transport_marker_menu_set_loop)));
511 items.push_back (MenuElem (_("Set Punch Range"), mem_fun(*this, &Editor::new_transport_marker_menu_set_punch)));
513 new_transport_marker_menu->signal_unmap_event().connect ( mem_fun(*this, &Editor::new_transport_marker_menu_popdown));
517 Editor::build_transport_marker_menu ()
519 using namespace Menu_Helpers;
521 transport_marker_menu = new Menu;
522 MenuList& items = transport_marker_menu->items();
523 transport_marker_menu->set_name ("ArdourContextMenu");
525 items.push_back (MenuElem (_("Locate to"), mem_fun(*this, &Editor::marker_menu_set_playhead)));
526 items.push_back (MenuElem (_("Play from"), mem_fun(*this, &Editor::marker_menu_play_from)));
527 items.push_back (MenuElem (_("Set from playhead"), mem_fun(*this, &Editor::marker_menu_set_from_playhead)));
528 items.push_back (MenuElem (_("Set from range"), mem_fun(*this, &Editor::marker_menu_set_from_selection)));
529 items.push_back (SeparatorElem());
530 items.push_back (MenuElem (_("Hide"), mem_fun(*this, &Editor::marker_menu_hide)));
535 Editor::marker_menu_hide ()
539 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
540 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
547 if ((l = find_location_from_marker (marker, is_start)) != 0) {
548 l->set_hidden (true, this);
553 Editor::marker_menu_select_all_from_range ()
557 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
558 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
564 if ((l = find_location_from_marker (marker, is_start)) != 0) {
566 select_all_within (l->start(), l->end(), 0, DBL_MAX, false);
572 Editor::marker_menu_play_from ()
576 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
577 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
584 if ((l = find_location_from_marker (marker, is_start)) != 0) {
587 session->request_locate (l->start(), true);
590 //session->request_bounded_roll (l->start(), l->end());
593 session->request_locate (l->start(), true);
595 session->request_locate (l->end(), true);
602 Editor::marker_menu_set_playhead ()
606 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
607 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
614 if ((l = find_location_from_marker (marker, is_start)) != 0) {
617 session->request_locate (l->start(), false);
621 session->request_locate (l->start(), false);
623 session->request_locate (l->end(), false);
630 Editor::marker_menu_set_from_playhead ()
634 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
635 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
642 if ((l = find_location_from_marker (marker, is_start)) != 0) {
645 l->set_start (session->transport_frame ());
649 l->set_start (session->transport_frame ());
651 l->set_end (session->transport_frame ());
658 Editor::marker_menu_set_from_selection ()
662 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
663 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
670 if ((l = find_location_from_marker (marker, is_start)) != 0) {
677 /* if range selection use first to last */
679 if (mouse_mode == Editing::MouseRange) {
680 if (!selection->time.empty()) {
681 l->set_start (selection->time.start());
682 l->set_end (selection->time.end_frame());
686 if (!selection->audio_regions.empty()) {
687 l->set_start (selection->audio_regions.start());
688 l->set_end (selection->audio_regions.end_frame());
696 Editor::marker_menu_loop_range ()
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;
708 if ((l = find_location_from_marker (marker, is_start)) != 0) {
710 if ((l2 = transport_loop_location()) != 0) {
711 l2->set (l->start(), l->end());
713 // enable looping, reposition and start rolling
714 session->request_auto_loop(true);
715 session->request_locate (l2->start(), true);
721 Editor::marker_menu_edit ()
727 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
728 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
732 if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
733 edit_meter_section (&mm->meter());
734 } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
735 edit_tempo_section (&tm->tempo());
737 fatal << X_("programming erorr: unhandled marker type in Editor::marker_menu_edit")
744 Editor::marker_menu_remove ()
750 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
751 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
755 if ((mm = dynamic_cast<MeterMarker*> (marker)) != 0) {
756 remove_meter_marker (marker_menu_item);
757 } else if ((tm = dynamic_cast<TempoMarker*> (marker)) != 0) {
758 remove_tempo_marker (marker_menu_item);
760 remove_marker (*marker_menu_item, (GdkEvent*) 0);
765 Editor::marker_menu_rename ()
769 if ((marker = reinterpret_cast<Marker *> (marker_menu_item->get_data ("marker"))) == 0) {
770 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
777 loc = find_location_from_marker (marker, is_start);
784 if (loc->is_mark()) {
785 dialog.set_title (_("ardour: rename mark"));
787 dialog.set_title (_("ardour: rename range"));
790 dialog.set_name ("MarkRenameWindow");
791 dialog.set_size_request (300, -1);
792 dialog.set_position (Gtk::WIN_POS_MOUSE);
793 dialog.set_modal (true);
795 dialog.add_action_widget (entry, RESPONSE_ACCEPT);
796 dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
797 dialog.add_button (Stock::CANCEL, RESPONSE_ACCEPT);
799 entry.set_text (loc->name());
800 entry.set_name ("MarkerNameDisplay");
805 switch (dialog.run ()) {
806 case RESPONSE_ACCEPT:
812 loc->set_name (entry.get_text());
816 Editor::new_transport_marker_menu_popdown (GdkEventAny *ev)
819 transport_bar_drag_rect->hide();
820 range_marker_drag_rect->hide();
826 Editor::new_transport_marker_menu_set_loop ()
828 if (!session) return;
830 begin_reversible_command (_("set loop range"));
834 if ((tll = transport_loop_location()) == 0) {
835 Location* loc = new Location (temp_location->start(), temp_location->end(), _("Loop"), Location::IsAutoLoop);
836 session->add_undo (session->locations()->get_memento());
837 session->locations()->add (loc, true);
838 session->set_auto_loop_location (loc);
839 session->add_redo_no_execute (session->locations()->get_memento());
842 session->add_undo (retype_return<void>(bind (mem_fun (*tll, &Location::set), tll->start(), tll->end())));
843 session->add_redo (retype_return<void>(bind (mem_fun (*tll, &Location::set), temp_location->start(), temp_location->end())));
844 tll->set_hidden (false, this);
845 tll->set (temp_location->start(), temp_location->end());
848 commit_reversible_command ();
852 Editor::new_transport_marker_menu_set_punch ()
854 if (!session) return;
856 begin_reversible_command (_("set punch range"));
860 if ((tpl = transport_punch_location()) == 0) {
861 tpl = new Location (temp_location->start(), temp_location->end(), _("Punch"), Location::IsAutoPunch);
862 session->add_undo (session->locations()->get_memento());
863 session->locations()->add (tpl, true);
864 session->set_auto_punch_location (tpl);
865 session->add_redo_no_execute (session->locations()->get_memento());
867 session->add_undo (retype_return<void>(bind (mem_fun (*tpl, &Location::set), tpl->start(), tpl->end())));
868 session->add_redo (retype_return<void>(bind (mem_fun (*tpl, &Location::set), temp_location->start(), temp_location->end())));
869 tpl->set_hidden(false, this);
870 tpl->set(temp_location->start(), temp_location->end());
873 commit_reversible_command ();
877 Editor::update_loop_range_view (bool visibility)
885 if (session->get_auto_loop() && ((tll = transport_loop_location()) != 0)) {
887 double x1 = frame_to_pixel (tll->start());
888 double x2 = frame_to_pixel (tll->end());
890 transport_loop_range_rect->property_x1() = x1;
891 transport_loop_range_rect->property_x2() = x2;
894 transport_loop_range_rect->show();
897 else if (visibility) {
898 transport_loop_range_rect->hide();
903 Editor::update_punch_range_view (bool visibility)
911 if ((session->get_punch_in() || session->get_punch_out()) && ((tpl = transport_punch_location()) != 0)) {
913 double x1 = frame_to_pixel (tpl->start());
914 double x2 = frame_to_pixel (tpl->end());
916 transport_punch_range_rect->property_x1() = x1;
917 transport_punch_range_rect->property_x2() = x2;
920 transport_punch_range_rect->show();
923 else if (visibility) {
924 transport_punch_range_rect->hide();
927 // if (session->get_punch_in()) {
928 // double x = frame_to_pixel (transport_punch_location->start());
929 // gnome_canvas_item_set (transport_punchin_line, "x1", x, "x2", x, NULL);
932 // gnome_canvas_item_show (transport_punchin_line);
935 // else if (visibility) {
936 // gnome_canvas_item_hide (transport_punchin_line);
939 // if (session->get_punch_out()) {
940 // double x = frame_to_pixel (transport_punch_location->end());
942 // gnome_canvas_item_set (transport_punchout_line, "x1", x, "x2", x, NULL);
945 // gnome_canvas_item_show (transport_punchout_line);
948 // else if (visibility) {
949 // gnome_canvas_item_hide (transport_punchout_line);