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.
23 #include <gtkmm2ext/utils.h>
25 #include "ardour/session.h"
26 #include "pbd/memento_command.h"
28 #include "ardour_ui.h"
29 #include "clock_group.h"
30 #include "main_clock.h"
31 #include "gui_thread.h"
33 #include "location_ui.h"
36 #include "public_editor.h"
41 using namespace ARDOUR;
42 using namespace ARDOUR_UI_UTILS;
45 using namespace Gtkmm2ext;
47 LocationEditRow::LocationEditRow(Session * sess, Location * loc, int32_t num)
48 : SessionHandlePtr (0) /* explicitly set below */
50 , item_table (1, 6, false)
51 , start_clock (X_("locationstart"), true, "", true, false)
52 , start_to_playhead_button (_("Use PH"))
53 , end_clock (X_("locationend"), true, "", true, false)
54 , end_to_playhead_button (_("Use PH"))
55 , length_clock (X_("locationlength"), true, "", true, false, true)
56 , cd_check_button (_("CD"))
57 , hide_check_button (_("Hide"))
58 , lock_check_button (_("Lock"))
59 , glue_check_button (_("Glue"))
62 i_am_the_modifier = 0;
64 remove_button.set_image (*manage (new Image (Stock::REMOVE, Gtk::ICON_SIZE_MENU)));
66 start_to_playhead_button.set_name ("LocationEditCdButton");
67 end_to_playhead_button.set_name ("LocationEditCdButton");
69 number_label.set_name ("LocationEditNumberLabel");
70 name_label.set_name ("LocationEditNameLabel");
71 name_entry.set_name ("LocationEditNameEntry");
72 cd_check_button.set_name ("LocationEditCdButton");
73 hide_check_button.set_name ("LocationEditHideButton");
74 lock_check_button.set_name ("LocationEditLockButton");
75 glue_check_button.set_name ("LocationEditGlueButton");
76 remove_button.set_name ("LocationEditRemoveButton");
77 isrc_label.set_name ("LocationEditNumberLabel");
78 isrc_entry.set_name ("LocationEditNameEntry");
79 scms_check_button.set_name ("LocationEditCdButton");
80 preemph_check_button.set_name ("LocationEditCdButton");
81 performer_label.set_name ("LocationEditNumberLabel");
82 performer_entry.set_name ("LocationEditNameEntry");
83 composer_label.set_name ("LocationEditNumberLabel");
84 composer_entry.set_name ("LocationEditNameEntry");
86 isrc_label.set_text (X_("ISRC:"));
87 performer_label.set_text (_("Performer:"));
88 composer_label.set_text (_("Composer:"));
89 scms_label.set_text (X_("SCMS"));
90 preemph_label.set_text (_("Pre-Emphasis"));
92 isrc_entry.set_size_request (112, -1);
93 isrc_entry.set_max_length(12);
94 isrc_entry.set_editable (true);
96 performer_entry.set_size_request (100, -1);
97 performer_entry.set_editable (true);
99 composer_entry.set_size_request (100, -1);
100 composer_entry.set_editable (true);
102 name_label.set_alignment (0, 0.5);
104 Gtk::HBox* front_spacing = manage (new HBox);
105 front_spacing->set_size_request (20, -1);
106 Gtk::HBox* mid_spacing = manage (new HBox);
107 mid_spacing->set_size_request (20, -1);
109 cd_track_details_hbox.set_spacing (4);
110 cd_track_details_hbox.pack_start (*front_spacing, false, false);
111 cd_track_details_hbox.pack_start (isrc_label, false, false);
112 cd_track_details_hbox.pack_start (isrc_entry, false, false);
113 cd_track_details_hbox.pack_start (performer_label, false, false);
114 cd_track_details_hbox.pack_start (performer_entry, true, true);
115 cd_track_details_hbox.pack_start (composer_label, false, false);
116 cd_track_details_hbox.pack_start (composer_entry, true, true);
117 cd_track_details_hbox.pack_start (*mid_spacing, false, false);
118 cd_track_details_hbox.pack_start (scms_label, false, false);
119 cd_track_details_hbox.pack_start (scms_check_button, false, false);
120 cd_track_details_hbox.pack_start (preemph_label, false, false);
121 cd_track_details_hbox.pack_start (preemph_check_button, false, false);
123 isrc_entry.signal_changed().connect (sigc::mem_fun(*this, &LocationEditRow::isrc_entry_changed));
124 performer_entry.signal_changed().connect (sigc::mem_fun(*this, &LocationEditRow::performer_entry_changed));
125 composer_entry.signal_changed().connect (sigc::mem_fun(*this, &LocationEditRow::composer_entry_changed));
126 scms_check_button.signal_toggled().connect(sigc::mem_fun(*this, &LocationEditRow::scms_toggled));
127 preemph_check_button.signal_toggled().connect(sigc::mem_fun(*this, &LocationEditRow::preemph_toggled));
131 start_hbox.set_spacing (2);
132 start_hbox.pack_start (start_clock, false, false);
133 start_hbox.pack_start (start_to_playhead_button, false, false);
135 /* this is always in this location, no matter what the location is */
137 VBox *rbox = manage (new VBox);
138 rbox->pack_start (remove_button, false, false);
140 item_table.attach (*rbox, 0, 1, 0, 1, FILL, Gtk::AttachOptions (0), 4, 0);
141 item_table.attach (start_hbox, 2, 3, 0, 1, FILL, Gtk::AttachOptions(0), 4, 0);
143 start_to_playhead_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &LocationEditRow::to_playhead_button_pressed), LocStart));
144 start_clock.ValueChanged.connect (sigc::bind (sigc::mem_fun (*this, &LocationEditRow::clock_changed), LocStart));
145 start_clock.signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &LocationEditRow::locate_to_clock), &start_clock), false);
147 end_hbox.set_spacing (2);
148 end_hbox.pack_start (end_clock, false, false);
149 end_hbox.pack_start (end_to_playhead_button, false, false);
151 end_to_playhead_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &LocationEditRow::to_playhead_button_pressed), LocEnd));
152 end_clock.ValueChanged.connect (sigc::bind (sigc::mem_fun (*this, &LocationEditRow::clock_changed), LocEnd));
153 end_clock.signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &LocationEditRow::locate_to_clock), &end_clock), false);
155 length_clock.ValueChanged.connect (sigc::bind ( sigc::mem_fun(*this, &LocationEditRow::clock_changed), LocLength));
157 cd_check_button.signal_toggled().connect(sigc::mem_fun(*this, &LocationEditRow::cd_toggled));
158 hide_check_button.signal_toggled().connect(sigc::mem_fun(*this, &LocationEditRow::hide_toggled));
159 lock_check_button.signal_toggled().connect(sigc::mem_fun(*this, &LocationEditRow::lock_toggled));
160 glue_check_button.signal_toggled().connect(sigc::mem_fun(*this, &LocationEditRow::glue_toggled));
162 remove_button.signal_clicked().connect(sigc::mem_fun(*this, &LocationEditRow::remove_button_pressed));
164 pack_start(item_table, true, true);
168 cd_toggled(); // show/hide cd-track details
171 LocationEditRow::~LocationEditRow()
174 connections.drop_connections ();
178 _clock_group->remove (start_clock);
179 _clock_group->remove (end_clock);
180 _clock_group->remove (length_clock);
185 LocationEditRow::set_clock_group (ClockGroup& cg)
188 _clock_group->remove (start_clock);
189 _clock_group->remove (end_clock);
190 _clock_group->remove (length_clock);
195 _clock_group->add (start_clock);
196 _clock_group->add (end_clock);
197 _clock_group->add (length_clock);
201 LocationEditRow::set_session (Session *sess)
203 SessionHandlePtr::set_session (sess);
209 start_clock.set_session (_session);
210 end_clock.set_session (_session);
211 length_clock.set_session (_session);
215 LocationEditRow::set_number (int num)
220 number_label.set_text (string_compose ("%1", number));
225 LocationEditRow::set_location (Location *loc)
228 connections.drop_connections ();
239 if (!hide_check_button.get_parent()) {
240 item_table.attach (hide_check_button, 6, 7, 0, 1, FILL, Gtk::FILL, 4, 0);
241 item_table.attach (lock_check_button, 7, 8, 0, 1, FILL, Gtk::FILL, 4, 0);
242 item_table.attach (glue_check_button, 8, 9, 0, 1, FILL, Gtk::FILL, 4, 0);
244 hide_check_button.set_active (location->is_hidden());
245 lock_check_button.set_active (location->locked());
246 glue_check_button.set_active (location->position_lock_style() == MusicTime);
248 if (location->is_auto_loop() || location-> is_auto_punch()) {
249 // use label instead of entry
251 name_label.set_text (location->name());
252 name_label.set_size_request (80, -1);
254 remove_button.hide ();
256 if (!name_label.get_parent()) {
257 item_table.attach (name_label, 1, 2, 0, 1, FILL, FILL, 4, 0);
264 name_entry.set_text (location->name());
265 name_entry.set_size_request (100, -1);
266 name_entry.set_editable (true);
267 name_entry.signal_changed().connect (sigc::mem_fun(*this, &LocationEditRow::name_entry_changed));
269 if (!name_entry.get_parent()) {
270 item_table.attach (name_entry, 1, 2, 0, 1, FILL | EXPAND, FILL, 4, 0);
274 if (!cd_check_button.get_parent()) {
275 item_table.attach (cd_check_button, 5, 6, 0, 1, FILL, Gtk::AttachOptions (0), 4, 0);
278 if (location->is_session_range()) {
279 remove_button.set_sensitive (false);
282 cd_check_button.set_active (location->is_cd_marker());
283 cd_check_button.show();
285 if (location->start() == _session->current_start_frame()) {
286 cd_check_button.set_sensitive (false);
288 cd_check_button.set_sensitive (true);
291 hide_check_button.show();
292 lock_check_button.show();
293 glue_check_button.show();
296 start_clock.set (location->start(), true);
299 if (!location->is_mark()) {
300 if (!end_hbox.get_parent()) {
301 item_table.attach (end_hbox, 3, 4, 0, 1, FILL, Gtk::AttachOptions (0), 4, 0);
303 if (!length_clock.get_parent()) {
304 end_hbox.pack_start (length_clock, false, false);
307 end_clock.set (location->end(), true);
308 length_clock.set (location->length(), true);
313 if (location->is_cd_marker()) {
314 show_cd_track_details ();
317 ARDOUR_UI::instance()->set_tip (remove_button, _("Remove this range"));
318 ARDOUR_UI::instance()->set_tip (start_clock, _("Start time - middle click to locate here"));
319 ARDOUR_UI::instance()->set_tip (end_clock, _("End time - middle click to locate here"));
320 ARDOUR_UI::instance()->set_tip (length_clock, _("Length"));
322 ARDOUR_UI::instance()->tooltips().set_tip (start_to_playhead_button, _("Set range start from playhead location"));
323 ARDOUR_UI::instance()->tooltips().set_tip (end_to_playhead_button, _("Set range end from playhead location"));
327 ARDOUR_UI::instance()->set_tip (remove_button, _("Remove this marker"));
328 ARDOUR_UI::instance()->set_tip (start_clock, _("Position - middle click to locate here"));
330 ARDOUR_UI::instance()->tooltips().set_tip (start_to_playhead_button, _("Set marker time from playhead location"));
336 set_clock_editable_status ();
340 /* connect to per-location signals, since this row only cares about this location */
342 location->NameChanged.connect (connections, invalidator (*this), boost::bind (&LocationEditRow::name_changed, this), gui_context());
343 location->StartChanged.connect (connections, invalidator (*this), boost::bind (&LocationEditRow::start_changed, this), gui_context());
344 location->EndChanged.connect (connections, invalidator (*this), boost::bind (&LocationEditRow::end_changed, this), gui_context());
345 location->Changed.connect (connections, invalidator (*this), boost::bind (&LocationEditRow::location_changed, this), gui_context());
346 location->FlagsChanged.connect (connections, invalidator (*this), boost::bind (&LocationEditRow::flags_changed, this), gui_context());
347 location->LockChanged.connect (connections, invalidator (*this), boost::bind (&LocationEditRow::lock_changed, this), gui_context());
348 location->PositionLockStyleChanged.connect (connections, invalidator (*this), boost::bind (&LocationEditRow::position_lock_style_changed, this), gui_context());
352 LocationEditRow::name_entry_changed ()
354 ENSURE_GUI_THREAD (*this, &LocationEditRow::name_entry_changed)
356 if (i_am_the_modifier || !location) {
360 location->set_name (name_entry.get_text());
365 LocationEditRow::isrc_entry_changed ()
367 ENSURE_GUI_THREAD (*this, &LocationEditRow::isrc_entry_changed)
369 if (i_am_the_modifier || !location) return;
371 if (isrc_entry.get_text() != "" ) {
373 location->cd_info["isrc"] = isrc_entry.get_text();
376 location->cd_info.erase("isrc");
381 LocationEditRow::performer_entry_changed ()
383 ENSURE_GUI_THREAD (*this, &LocationEditRow::performer_entry_changed)
385 if (i_am_the_modifier || !location) return;
387 if (performer_entry.get_text() != "") {
388 location->cd_info["performer"] = performer_entry.get_text();
390 location->cd_info.erase("performer");
395 LocationEditRow::composer_entry_changed ()
397 ENSURE_GUI_THREAD (*this, &LocationEditRow::composer_entry_changed)
399 if (i_am_the_modifier || !location) return;
401 if (composer_entry.get_text() != "") {
402 location->cd_info["composer"] = composer_entry.get_text();
404 location->cd_info.erase("composer");
409 LocationEditRow::to_playhead_button_pressed (LocationPart part)
417 location->set_start (_session->transport_frame ());
420 location->set_end (_session->transport_frame ());
428 LocationEditRow::locate_to_clock (GdkEventButton* ev, AudioClock* clock)
430 if (Keyboard::is_button2_event (ev)) {
431 _session->request_locate (clock->current_time());
438 LocationEditRow::clock_changed (LocationPart part)
440 if (i_am_the_modifier || !location) {
446 location->set_start (start_clock.current_time());
449 location->set_end (end_clock.current_time());
452 location->set_end (location->start() + length_clock.current_duration());
459 LocationEditRow::show_cd_track_details ()
462 if (location->cd_info.find("isrc") != location->cd_info.end()) {
463 isrc_entry.set_text(location->cd_info["isrc"]);
465 if (location->cd_info.find("performer") != location->cd_info.end()) {
466 performer_entry.set_text(location->cd_info["performer"]);
468 if (location->cd_info.find("composer") != location->cd_info.end()) {
469 composer_entry.set_text(location->cd_info["composer"]);
471 if (location->cd_info.find("scms") != location->cd_info.end()) {
472 scms_check_button.set_active(true);
474 if (location->cd_info.find("preemph") != location->cd_info.end()) {
475 preemph_check_button.set_active(true);
479 if (!cd_track_details_hbox.get_parent()) {
480 item_table.attach (cd_track_details_hbox, 0, 7, 1, 2, FILL | EXPAND, FILL, 4, 0);
482 // item_table.resize(2, 7);
483 cd_track_details_hbox.show_all();
487 LocationEditRow::cd_toggled ()
489 if (i_am_the_modifier || !location) {
493 //if (cd_check_button.get_active() == location->is_cd_marker()) {
497 if (cd_check_button.get_active()) {
498 if (location->start() <= _session->current_start_frame()) {
499 error << _("You cannot put a CD marker at the start of the session") << endmsg;
500 cd_check_button.set_active (false);
505 location->set_cd (cd_check_button.get_active(), this);
507 if (location->is_cd_marker()) {
509 show_cd_track_details ();
511 } else if (cd_track_details_hbox.get_parent()){
513 item_table.remove (cd_track_details_hbox);
514 // item_table.resize(1, 7);
515 redraw_ranges(); /* EMIT_SIGNAL */
520 LocationEditRow::hide_toggled ()
522 if (i_am_the_modifier || !location) {
526 location->set_hidden (hide_check_button.get_active(), this);
530 LocationEditRow::lock_toggled ()
532 if (i_am_the_modifier || !location) {
536 if (location->locked()) {
544 LocationEditRow::glue_toggled ()
546 if (i_am_the_modifier || !location) {
550 if (location->position_lock_style() == AudioTime) {
551 location->set_position_lock_style (MusicTime);
553 location->set_position_lock_style (AudioTime);
558 LocationEditRow::remove_button_pressed ()
564 remove_requested (location); /* EMIT_SIGNAL */
570 LocationEditRow::scms_toggled ()
572 if (i_am_the_modifier || !location) return;
574 if (scms_check_button.get_active()) {
575 location->cd_info["scms"] = "on";
577 location->cd_info.erase("scms");
583 LocationEditRow::preemph_toggled ()
585 if (i_am_the_modifier || !location) return;
587 if (preemph_check_button.get_active()) {
588 location->cd_info["preemph"] = "on";
590 location->cd_info.erase("preemph");
595 LocationEditRow::end_changed ()
597 ENSURE_GUI_THREAD (*this, &LocationEditRow::end_changed, loc)
599 if (!location) return;
601 // update end and length
604 end_clock.set (location->end());
605 length_clock.set (location->length());
611 LocationEditRow::start_changed ()
613 if (!location) return;
615 // update end and length
618 start_clock.set (location->start());
620 if (location->start() == _session->current_start_frame()) {
621 cd_check_button.set_sensitive (false);
623 cd_check_button.set_sensitive (true);
630 LocationEditRow::name_changed ()
632 if (!location) return;
634 // update end and length
637 name_entry.set_text(location->name());
638 name_label.set_text(location->name());
645 LocationEditRow::location_changed ()
648 if (!location) return;
652 start_clock.set (location->start());
653 end_clock.set (location->end());
654 length_clock.set (location->length());
656 set_clock_editable_status ();
663 LocationEditRow::flags_changed ()
671 cd_check_button.set_active (location->is_cd_marker());
672 hide_check_button.set_active (location->is_hidden());
673 glue_check_button.set_active (location->position_lock_style() == MusicTime);
679 LocationEditRow::lock_changed ()
687 lock_check_button.set_active (location->locked());
689 set_clock_editable_status ();
695 LocationEditRow::position_lock_style_changed ()
703 glue_check_button.set_active (location->position_lock_style() == MusicTime);
709 LocationEditRow::focus_name()
711 name_entry.grab_focus ();
715 LocationEditRow::set_clock_editable_status ()
717 start_clock.set_editable (!location->locked());
718 end_clock.set_editable (!location->locked());
719 length_clock.set_editable (!location->locked());
722 /*------------------------------------------------------------------------*/
724 LocationUI::LocationUI ()
725 : add_location_button (_("New Marker"))
726 , add_range_button (_("New Range"))
728 i_am_the_modifier = 0;
730 _clock_group = new ClockGroup;
732 VBox* vbox = manage (new VBox);
734 Table* table = manage (new Table (2, 2));
735 table->set_spacings (2);
736 table->set_col_spacing (0, 32);
739 Label* l = manage (new Label (_("<b>Loop/Punch Ranges</b>")));
740 l->set_alignment (0, 0.5);
741 l->set_use_markup (true);
742 table->attach (*l, 0, 2, table_row, table_row + 1);
745 loop_edit_row.set_clock_group (*_clock_group);
746 punch_edit_row.set_clock_group (*_clock_group);
748 loop_punch_box.pack_start (loop_edit_row, false, false);
749 loop_punch_box.pack_start (punch_edit_row, false, false);
751 table->attach (loop_punch_box, 1, 2, table_row, table_row + 1);
754 vbox->pack_start (*table, false, false);
756 table = manage (new Table (3, 2));
757 table->set_spacings (2);
758 table->set_col_spacing (0, 32);
761 table->attach (*manage (new Label ("")), 0, 2, table_row, table_row + 1, Gtk::SHRINK, Gtk::SHRINK);
764 l = manage (new Label (_("<b>Markers (Including CD Index)</b>")));
765 l->set_alignment (0, 0.5);
766 l->set_use_markup (true);
767 table->attach (*l, 0, 2, table_row, table_row + 1, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
770 location_rows.set_name("LocationLocRows");
771 location_rows_scroller.add (location_rows);
772 location_rows_scroller.set_name ("LocationLocRowsScroller");
773 location_rows_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
774 location_rows_scroller.set_size_request (-1, 130);
778 loc_frame_box.set_spacing (5);
779 loc_frame_box.set_border_width (5);
780 loc_frame_box.set_name("LocationFrameBox");
782 loc_frame_box.pack_start (location_rows_scroller, true, true);
784 add_location_button.set_name ("LocationAddLocationButton");
786 table->attach (loc_frame_box, 0, 2, table_row, table_row + 1);
789 loc_range_panes.pack1 (*table, true, false);
791 table = manage (new Table (3, 2));
792 table->set_spacings (2);
793 table->set_col_spacing (0, 32);
796 table->attach (*manage (new Label ("")), 0, 2, table_row, table_row + 1, Gtk::SHRINK, Gtk::SHRINK);
799 l = manage (new Label (_("<b>Ranges (Including CD Track Ranges)</b>")));
800 l->set_alignment (0, 0.5);
801 l->set_use_markup (true);
802 table->attach (*l, 0, 2, table_row, table_row + 1, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK);
805 range_rows.set_name("LocationRangeRows");
806 range_rows_scroller.add (range_rows);
807 range_rows_scroller.set_name ("LocationRangeRowsScroller");
808 range_rows_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
809 range_rows_scroller.set_size_request (-1, 130);
811 range_frame_box.set_spacing (5);
812 range_frame_box.set_name("LocationFrameBox");
813 range_frame_box.set_border_width (5);
814 range_frame_box.pack_start (range_rows_scroller, true, true);
816 add_range_button.set_name ("LocationAddRangeButton");
818 table->attach (range_frame_box, 0, 2, table_row, table_row + 1);
821 loc_range_panes.pack2 (*table, true, false);
823 HBox* add_button_box = manage (new HBox);
824 add_button_box->pack_start (add_location_button, true, true);
825 add_button_box->pack_start (add_range_button, true, true);
827 vbox->pack_start (loc_range_panes, true, true);
828 vbox->pack_start (*add_button_box, false, false);
832 add_location_button.signal_clicked().connect (sigc::mem_fun(*this, &LocationUI::add_new_location));
833 add_range_button.signal_clicked().connect (sigc::mem_fun(*this, &LocationUI::add_new_range));
837 signal_map().connect (sigc::mem_fun (*this, &LocationUI::refresh_location_list));
840 LocationUI::~LocationUI()
842 loop_edit_row.unset_clock_group ();
843 punch_edit_row.unset_clock_group ();
848 LocationUI::do_location_remove (ARDOUR::Location *loc)
850 /* this is handled internally by Locations, but there's
851 no point saving state etc. when we know the marker
855 if (loc->is_session_range()) {
859 PublicEditor::instance().begin_reversible_command (_("remove marker"));
860 XMLNode &before = _session->locations()->get_state();
861 _session->locations()->remove (loc);
862 XMLNode &after = _session->locations()->get_state();
863 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
864 PublicEditor::instance().commit_reversible_command ();
870 LocationUI::location_remove_requested (ARDOUR::Location *loc)
872 // must do this to prevent problems when destroying
873 // the effective sender of this event
875 Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &LocationUI::do_location_remove), loc));
880 LocationUI::location_redraw_ranges ()
886 struct LocationSortByStart {
887 bool operator() (Location *a, Location *b) {
888 return a->start() < b->start();
893 LocationUI::location_added (Location* location)
895 if (location->is_auto_punch()) {
896 punch_edit_row.set_location(location);
897 } else if (location->is_auto_loop()) {
898 loop_edit_row.set_location(location);
899 } else if (location->is_range_marker() || location->is_mark()) {
900 Locations::LocationList loc = _session->locations()->list ();
901 loc.sort (LocationSortByStart ());
903 LocationEditRow* erow = manage (new LocationEditRow (_session, location));
905 erow->set_clock_group (*_clock_group);
906 erow->remove_requested.connect (sigc::mem_fun (*this, &LocationUI::location_remove_requested));
908 Box_Helpers::BoxList & children = location->is_range_marker() ? range_rows.children () : location_rows.children ();
910 /* Step through the location list and the GUI list to find the place to insert */
911 Locations::LocationList::iterator i = loc.begin ();
912 Box_Helpers::BoxList::iterator j = children.begin ();
913 while (i != loc.end()) {
915 if (location->flags() != (*i)->flags()) {
916 /* Skip locations in the session list that aren't of the right type */
921 if (*i == location) {
922 children.insert (j, Box_Helpers::Element (*erow, PACK_SHRINK, 1, PACK_START));
928 if (j != children.end()) {
933 range_rows.show_all ();
934 location_rows.show_all ();
936 if (location == newest_location) {
944 LocationUI::location_removed (Location* location)
946 ENSURE_GUI_THREAD (*this, &LocationUI::location_removed, location)
948 if (location->is_auto_punch()) {
949 punch_edit_row.set_location(0);
950 } else if (location->is_auto_loop()) {
951 loop_edit_row.set_location(0);
952 } else if (location->is_range_marker() || location->is_mark()) {
953 Box_Helpers::BoxList& children = location->is_range_marker() ? range_rows.children () : location_rows.children ();
954 for (Box_Helpers::BoxList::iterator i = children.begin(); i != children.end(); ++i) {
955 LocationEditRow* r = dynamic_cast<LocationEditRow*> (i->get_widget());
956 if (r && r->get_location() == location) {
965 LocationUI::map_locations (const Locations::LocationList& locations)
967 Locations::LocationList::iterator i;
970 Locations::LocationList temp = locations;
971 LocationSortByStart cmp;
975 for (n = 0, i = temp.begin(); i != temp.end(); ++n, ++i) {
977 Location* location = *i;
979 if (location->is_mark()) {
980 LocationEditRow* erow = manage (new LocationEditRow (_session, location, mark_n));
982 erow->set_clock_group (*_clock_group);
983 erow->remove_requested.connect (sigc::mem_fun(*this, &LocationUI::location_remove_requested));
984 erow->redraw_ranges.connect (sigc::mem_fun(*this, &LocationUI::location_redraw_ranges));
986 Box_Helpers::BoxList & loc_children = location_rows.children();
987 loc_children.push_back(Box_Helpers::Element(*erow, PACK_SHRINK, 1, PACK_START));
988 } else if (location->is_auto_punch()) {
989 punch_edit_row.set_session (_session);
990 punch_edit_row.set_location (location);
991 punch_edit_row.show_all();
992 } else if (location->is_auto_loop()) {
993 loop_edit_row.set_session (_session);
994 loop_edit_row.set_location (location);
995 loop_edit_row.show_all();
997 LocationEditRow* erow = manage (new LocationEditRow(_session, location));
999 erow->set_clock_group (*_clock_group);
1000 erow->remove_requested.connect (sigc::mem_fun(*this, &LocationUI::location_remove_requested));
1002 Box_Helpers::BoxList & range_children = range_rows.children();
1003 range_children.push_back(Box_Helpers::Element(*erow, PACK_SHRINK, 1, PACK_START));
1007 range_rows.show_all();
1008 location_rows.show_all();
1012 LocationUI::add_new_location()
1017 framepos_t where = _session->audible_frame();
1018 _session->locations()->next_available_name(markername,"mark");
1019 Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1020 if (ARDOUR_UI::config()->get_name_new_markers()) {
1021 newest_location = location;
1023 PublicEditor::instance().begin_reversible_command (_("add marker"));
1024 XMLNode &before = _session->locations()->get_state();
1025 _session->locations()->add (location, true);
1026 XMLNode &after = _session->locations()->get_state();
1027 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1028 PublicEditor::instance().commit_reversible_command ();
1034 LocationUI::add_new_range()
1039 framepos_t where = _session->audible_frame();
1040 _session->locations()->next_available_name(rangename,"unnamed");
1041 Location *location = new Location (*_session, where, where, rangename, Location::IsRangeMarker);
1042 PublicEditor::instance().begin_reversible_command (_("add range marker"));
1043 XMLNode &before = _session->locations()->get_state();
1044 _session->locations()->add (location, true);
1045 XMLNode &after = _session->locations()->get_state();
1046 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1047 PublicEditor::instance().commit_reversible_command ();
1052 LocationUI::refresh_location_list ()
1054 ENSURE_GUI_THREAD (*this, &LocationUI::refresh_location_list)
1055 using namespace Box_Helpers;
1057 // this is just too expensive to do when window is not shown
1062 BoxList & loc_children = location_rows.children();
1063 BoxList & range_children = range_rows.children();
1065 loc_children.clear();
1066 range_children.clear();
1069 _session->locations()->apply (*this, &LocationUI::map_locations);
1074 LocationUI::set_session(ARDOUR::Session* s)
1076 SessionHandlePtr::set_session (s);
1079 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&LocationUI::location_added, this, _1), gui_context());
1080 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&LocationUI::location_removed, this, _1), gui_context());
1081 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&LocationUI::refresh_location_list, this), gui_context());
1083 _clock_group->set_clock_mode (clock_mode_from_session_instant_xml ());
1086 loop_edit_row.set_session (s);
1087 punch_edit_row.set_session (s);
1089 refresh_location_list ();
1093 LocationUI::session_going_away()
1095 ENSURE_GUI_THREAD (*this, &LocationUI::session_going_away);
1097 using namespace Box_Helpers;
1098 BoxList & loc_children = location_rows.children();
1099 BoxList & range_children = range_rows.children();
1101 loc_children.clear();
1102 range_children.clear();
1104 loop_edit_row.set_session (0);
1105 loop_edit_row.set_location (0);
1107 punch_edit_row.set_session (0);
1108 punch_edit_row.set_location (0);
1110 SessionHandlePtr::session_going_away ();
1114 LocationUI::get_state () const
1116 XMLNode* node = new XMLNode (X_("LocationUI"));
1117 node->add_property (X_("clock-mode"), enum_2_string (_clock_group->clock_mode ()));
1122 LocationUI::clock_mode_from_session_instant_xml () const
1124 XMLNode* node = _session->instant_xml (X_("LocationUI"));
1126 return AudioClock::Frames;
1129 XMLProperty* p = node->property (X_("clock-mode"));
1131 return ARDOUR_UI::instance()->secondary_clock->mode();
1134 return (AudioClock::Mode) string_2_enum (p->value (), AudioClock::Mode);
1138 /*------------------------*/
1140 LocationUIWindow::LocationUIWindow ()
1141 : ArdourWindow (_("Locations"))
1143 set_wmclass(X_("ardour_locations"), PROGRAM_NAME);
1144 set_name ("LocationWindow");
1149 LocationUIWindow::~LocationUIWindow()
1154 LocationUIWindow::on_map ()
1156 ArdourWindow::on_map ();
1157 _ui.refresh_location_list();
1161 LocationUIWindow::on_delete_event (GdkEventAny*)
1167 LocationUIWindow::set_session (Session *s)
1169 ArdourWindow::set_session (s);
1170 _ui.set_session (s);
1175 LocationUIWindow::session_going_away ()
1177 ArdourWindow::session_going_away ();