ardour
location_ui.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000 Paul Davis
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18 */
19 
20 #include <cmath>
21 #include <cstdlib>
22 
23 #include <gtkmm2ext/utils.h>
24 
25 #include "ardour/session.h"
26 #include "pbd/memento_command.h"
27 
28 #include "ardour_ui.h"
29 #include "clock_group.h"
30 #include "main_clock.h"
31 #include "gui_thread.h"
32 #include "keyboard.h"
33 #include "location_ui.h"
34 #include "prompter.h"
35 #include "utils.h"
36 #include "public_editor.h"
37 
38 #include "i18n.h"
39 
40 using namespace std;
41 using namespace ARDOUR;
42 using namespace ARDOUR_UI_UTILS;
43 using namespace PBD;
44 using namespace Gtk;
45 using namespace Gtkmm2ext;
46 
48  : SessionHandlePtr (0) /* explicitly set below */
49  , location(0)
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"))
60  , _clock_group (0)
61 {
63 
64  remove_button.set_image (*manage (new Image (Stock::REMOVE, Gtk::ICON_SIZE_MENU)));
65 
66  start_to_playhead_button.set_name ("LocationEditCdButton");
67  end_to_playhead_button.set_name ("LocationEditCdButton");
68 
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");
85 
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"));
91 
92  isrc_entry.set_size_request (112, -1);
93  isrc_entry.set_max_length(12);
94  isrc_entry.set_editable (true);
95 
96  performer_entry.set_size_request (100, -1);
97  performer_entry.set_editable (true);
98 
99  composer_entry.set_size_request (100, -1);
100  composer_entry.set_editable (true);
101 
102  name_label.set_alignment (0, 0.5);
103 
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);
108 
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);
122 
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));
128 
129  set_session (sess);
130 
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);
134 
135  /* this is always in this location, no matter what the location is */
136 
137  VBox *rbox = manage (new VBox);
138  rbox->pack_start (remove_button, false, false);
139 
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);
142 
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);
146 
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);
150 
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);
154 
155  length_clock.ValueChanged.connect (sigc::bind ( sigc::mem_fun(*this, &LocationEditRow::clock_changed), LocLength));
156 
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));
161 
162  remove_button.signal_clicked().connect(sigc::mem_fun(*this, &LocationEditRow::remove_button_pressed));
163 
164  pack_start(item_table, true, true);
165 
166  set_location (loc);
167  set_number (num);
168  cd_toggled(); // show/hide cd-track details
169  }
170 
172  {
173  if (location) {
175  }
176 
177  if (_clock_group) {
181  }
182  }
183 
184  void
186  {
187  if (_clock_group) {
191  }
192 
193  _clock_group = &cg;
194 
198 }
199 
200 void
202 {
203  SessionHandlePtr::set_session (sess);
204 
205  if (!_session) {
206  return;
207  }
208 
212 }
213 
214 void
216 {
217  number = num;
218 
219  if (number >= 0 ) {
220  number_label.set_text (string_compose ("%1", number));
221  }
222 }
223 
224 void
226 {
227  if (location) {
229  }
230 
231  location = loc;
232 
233  if (!location) {
234  return;
235  }
236 
238 
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);
243  }
244  hide_check_button.set_active (location->is_hidden());
245  lock_check_button.set_active (location->locked());
247 
248  if (location->is_auto_loop() || location-> is_auto_punch()) {
249  // use label instead of entry
250 
251  name_label.set_text (location->name());
252  name_label.set_size_request (80, -1);
253 
254  remove_button.hide ();
255 
256  if (!name_label.get_parent()) {
257  item_table.attach (name_label, 1, 2, 0, 1, FILL, FILL, 4, 0);
258  }
259 
260  name_label.show();
261 
262  } else {
263 
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));
268 
269  if (!name_entry.get_parent()) {
270  item_table.attach (name_entry, 1, 2, 0, 1, FILL | EXPAND, FILL, 4, 0);
271  }
272  name_entry.show();
273 
274  if (!cd_check_button.get_parent()) {
275  item_table.attach (cd_check_button, 5, 6, 0, 1, FILL, Gtk::AttachOptions (0), 4, 0);
276  }
277 
278  if (location->is_session_range()) {
279  remove_button.set_sensitive (false);
280  }
281 
282  cd_check_button.set_active (location->is_cd_marker());
283  cd_check_button.show();
284 
286  cd_check_button.set_sensitive (false);
287  } else {
288  cd_check_button.set_sensitive (true);
289  }
290 
291  hide_check_button.show();
292  lock_check_button.show();
293  glue_check_button.show();
294  }
295 
296  start_clock.set (location->start(), true);
297 
298 
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);
302  }
303  if (!length_clock.get_parent()) {
304  end_hbox.pack_start (length_clock, false, false);
305  }
306 
307  end_clock.set (location->end(), true);
308  length_clock.set (location->length(), true);
309 
310  end_clock.show();
311  length_clock.show();
312 
313  if (location->is_cd_marker()) {
315  }
316 
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"));
321 
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"));
324 
325  } else {
326 
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"));
329 
330  ARDOUR_UI::instance()->tooltips().set_tip (start_to_playhead_button, _("Set marker time from playhead location"));
331 
332  end_clock.hide();
333  length_clock.hide();
334  }
335 
337 
339 
340  /* connect to per-location signals, since this row only cares about this location */
341 
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());
349 }
350 
351 void
353 {
355 
356  if (i_am_the_modifier || !location) {
357  return;
358  }
359 
360  location->set_name (name_entry.get_text());
361 }
362 
363 
364 void
366 {
368 
369  if (i_am_the_modifier || !location) return;
370 
371  if (isrc_entry.get_text() != "" ) {
372 
373  location->cd_info["isrc"] = isrc_entry.get_text();
374 
375  } else {
376  location->cd_info.erase("isrc");
377  }
378 }
379 
380 void
382 {
384 
385  if (i_am_the_modifier || !location) return;
386 
387  if (performer_entry.get_text() != "") {
388  location->cd_info["performer"] = performer_entry.get_text();
389  } else {
390  location->cd_info.erase("performer");
391  }
392 }
393 
394 void
396 {
398 
399  if (i_am_the_modifier || !location) return;
400 
401  if (composer_entry.get_text() != "") {
402  location->cd_info["composer"] = composer_entry.get_text();
403  } else {
404  location->cd_info.erase("composer");
405  }
406 }
407 
408 void
410 {
411  if (!location) {
412  return;
413  }
414 
415  switch (part) {
416  case LocStart:
418  break;
419  case LocEnd:
421  break;
422  default:
423  break;
424  }
425 }
426 
427 bool
428 LocationEditRow::locate_to_clock (GdkEventButton* ev, AudioClock* clock)
429 {
430  if (Keyboard::is_button2_event (ev)) {
432  return true;
433  }
434  return false;
435 }
436 
437 void
439 {
440  if (i_am_the_modifier || !location) {
441  return;
442  }
443 
444  switch (part) {
445  case LocStart:
447  break;
448  case LocEnd:
450  break;
451  case LocLength:
453  default:
454  break;
455  }
456 }
457 
458 void
460 {
461 
462  if (location->cd_info.find("isrc") != location->cd_info.end()) {
463  isrc_entry.set_text(location->cd_info["isrc"]);
464  }
465  if (location->cd_info.find("performer") != location->cd_info.end()) {
466  performer_entry.set_text(location->cd_info["performer"]);
467  }
468  if (location->cd_info.find("composer") != location->cd_info.end()) {
469  composer_entry.set_text(location->cd_info["composer"]);
470  }
471  if (location->cd_info.find("scms") != location->cd_info.end()) {
472  scms_check_button.set_active(true);
473  }
474  if (location->cd_info.find("preemph") != location->cd_info.end()) {
475  preemph_check_button.set_active(true);
476  }
477 
478 
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);
481  }
482  // item_table.resize(2, 7);
483  cd_track_details_hbox.show_all();
484 }
485 
486 void
488 {
489  if (i_am_the_modifier || !location) {
490  return;
491  }
492 
493  //if (cd_check_button.get_active() == location->is_cd_marker()) {
494  // return;
495  //}
496 
497  if (cd_check_button.get_active()) {
499  error << _("You cannot put a CD marker at the start of the session") << endmsg;
500  cd_check_button.set_active (false);
501  return;
502  }
503  }
504 
505  location->set_cd (cd_check_button.get_active(), this);
506 
507  if (location->is_cd_marker()) {
508 
510 
511  } else if (cd_track_details_hbox.get_parent()){
512 
514  // item_table.resize(1, 7);
515  redraw_ranges(); /* EMIT_SIGNAL */
516  }
517 }
518 
519 void
521 {
522  if (i_am_the_modifier || !location) {
523  return;
524  }
525 
526  location->set_hidden (hide_check_button.get_active(), this);
527 }
528 
529 void
531 {
532  if (i_am_the_modifier || !location) {
533  return;
534  }
535 
536  if (location->locked()) {
537  location->unlock ();
538  } else {
539  location->lock ();
540  }
541 }
542 
543 void
545 {
546  if (i_am_the_modifier || !location) {
547  return;
548  }
549 
552  } else {
554  }
555 }
556 
557 void
559 {
560  if (!location) {
561  return;
562  }
563 
564  remove_requested (location); /* EMIT_SIGNAL */
565 }
566 
567 
568 
569 void
571 {
572  if (i_am_the_modifier || !location) return;
573 
574  if (scms_check_button.get_active()) {
575  location->cd_info["scms"] = "on";
576  } else {
577  location->cd_info.erase("scms");
578  }
579 
580 }
581 
582 void
584 {
585  if (i_am_the_modifier || !location) return;
586 
587  if (preemph_check_button.get_active()) {
588  location->cd_info["preemph"] = "on";
589  } else {
590  location->cd_info.erase("preemph");
591  }
592 }
593 
594 void
596 {
598 
599  if (!location) return;
600 
601  // update end and length
603 
604  end_clock.set (location->end());
606 
608 }
609 
610 void
612 {
613  if (!location) return;
614 
615  // update end and length
617 
619 
621  cd_check_button.set_sensitive (false);
622  } else {
623  cd_check_button.set_sensitive (true);
624  }
625 
627 }
628 
629 void
631 {
632  if (!location) return;
633 
634  // update end and length
636 
637  name_entry.set_text(location->name());
638  name_label.set_text(location->name());
639 
641 
642 }
643 
644 void
646 {
647 
648  if (!location) return;
649 
651 
653  end_clock.set (location->end());
655 
657 
659 
660 }
661 
662 void
664 {
665  if (!location) {
666  return;
667  }
668 
670 
671  cd_check_button.set_active (location->is_cd_marker());
672  hide_check_button.set_active (location->is_hidden());
674 
676 }
677 
678 void
680 {
681  if (!location) {
682  return;
683  }
684 
686 
687  lock_check_button.set_active (location->locked());
688 
690 
692 }
693 
694 void
696 {
697  if (!location) {
698  return;
699  }
700 
702 
704 
706 }
707 
708 void
710 {
711  name_entry.grab_focus ();
712 }
713 
714 void
716 {
720 }
721 
722 /*------------------------------------------------------------------------*/
723 
725  : add_location_button (_("New Marker"))
726  , add_range_button (_("New Range"))
727 {
728  i_am_the_modifier = 0;
729 
730  _clock_group = new ClockGroup;
731 
732  VBox* vbox = manage (new VBox);
733 
734  Table* table = manage (new Table (2, 2));
735  table->set_spacings (2);
736  table->set_col_spacing (0, 32);
737  int table_row = 0;
738 
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);
743  ++table_row;
744 
747 
748  loop_punch_box.pack_start (loop_edit_row, false, false);
749  loop_punch_box.pack_start (punch_edit_row, false, false);
750 
751  table->attach (loop_punch_box, 1, 2, table_row, table_row + 1);
752  ++table_row;
753 
754  vbox->pack_start (*table, false, false);
755 
756  table = manage (new Table (3, 2));
757  table->set_spacings (2);
758  table->set_col_spacing (0, 32);
759  table_row = 0;
760 
761  table->attach (*manage (new Label ("")), 0, 2, table_row, table_row + 1, Gtk::SHRINK, Gtk::SHRINK);
762  ++table_row;
763 
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);
768  ++table_row;
769 
770  location_rows.set_name("LocationLocRows");
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);
775 
776  newest_location = 0;
777 
778  loc_frame_box.set_spacing (5);
779  loc_frame_box.set_border_width (5);
780  loc_frame_box.set_name("LocationFrameBox");
781 
782  loc_frame_box.pack_start (location_rows_scroller, true, true);
783 
784  add_location_button.set_name ("LocationAddLocationButton");
785 
786  table->attach (loc_frame_box, 0, 2, table_row, table_row + 1);
787  ++table_row;
788 
789  loc_range_panes.pack1 (*table, true, false);
790 
791  table = manage (new Table (3, 2));
792  table->set_spacings (2);
793  table->set_col_spacing (0, 32);
794  table_row = 0;
795 
796  table->attach (*manage (new Label ("")), 0, 2, table_row, table_row + 1, Gtk::SHRINK, Gtk::SHRINK);
797  ++table_row;
798 
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);
803  ++table_row;
804 
805  range_rows.set_name("LocationRangeRows");
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);
810 
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);
815 
816  add_range_button.set_name ("LocationAddRangeButton");
817 
818  table->attach (range_frame_box, 0, 2, table_row, table_row + 1);
819  ++table_row;
820 
821  loc_range_panes.pack2 (*table, true, false);
822 
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);
826 
827  vbox->pack_start (loc_range_panes, true, true);
828  vbox->pack_start (*add_button_box, false, false);
829 
830  pack_start (*vbox);
831 
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));
834 
835  show_all ();
836 
837  signal_map().connect (sigc::mem_fun (*this, &LocationUI::refresh_location_list));
838 }
839 
841 {
844  delete _clock_group;
845 }
846 
847 gint
849 {
850  /* this is handled internally by Locations, but there's
851  no point saving state etc. when we know the marker
852  cannot be removed.
853  */
854 
855  if (loc->is_session_range()) {
856  return FALSE;
857  }
858 
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));
865 
866  return FALSE;
867 }
868 
869 void
871 {
872  // must do this to prevent problems when destroying
873  // the effective sender of this event
874 
875  Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &LocationUI::do_location_remove), loc));
876 }
877 
878 
879 void
881 {
882  range_rows.hide();
883  range_rows.show();
884 }
885 
888  return a->start() < b->start();
889  }
890 };
891 
892 void
894 {
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()) {
901  loc.sort (LocationSortByStart ());
902 
903  LocationEditRow* erow = manage (new LocationEditRow (_session, location));
904 
905  erow->set_clock_group (*_clock_group);
906  erow->remove_requested.connect (sigc::mem_fun (*this, &LocationUI::location_remove_requested));
907 
908  Box_Helpers::BoxList & children = location->is_range_marker() ? range_rows.children () : location_rows.children ();
909 
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()) {
914 
915  if (location->flags() != (*i)->flags()) {
916  /* Skip locations in the session list that aren't of the right type */
917  ++i;
918  continue;
919  }
920 
921  if (*i == location) {
922  children.insert (j, Box_Helpers::Element (*erow, PACK_SHRINK, 1, PACK_START));
923  break;
924  }
925 
926  ++i;
927 
928  if (j != children.end()) {
929  ++j;
930  }
931  }
932 
933  range_rows.show_all ();
934  location_rows.show_all ();
935 
936  if (location == newest_location) {
937  newest_location = 0;
938  erow->focus_name();
939  }
940  }
941 }
942 
943 void
945 {
947 
948  if (location->is_auto_punch()) {
950  } else if (location->is_auto_loop()) {
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) {
957  children.erase (i);
958  break;
959  }
960  }
961  }
962 }
963 
964 void
966 {
967  Locations::LocationList::iterator i;
968  gint n;
969  int mark_n = 0;
970  Locations::LocationList temp = locations;
972 
973  temp.sort (cmp);
974 
975  for (n = 0, i = temp.begin(); i != temp.end(); ++n, ++i) {
976 
977  Location* location = *i;
978 
979  if (location->is_mark()) {
980  LocationEditRow* erow = manage (new LocationEditRow (_session, location, mark_n));
981 
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));
985 
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()) {
990  punch_edit_row.set_location (location);
991  punch_edit_row.show_all();
992  } else if (location->is_auto_loop()) {
994  loop_edit_row.set_location (location);
995  loop_edit_row.show_all();
996  } else {
997  LocationEditRow* erow = manage (new LocationEditRow(_session, location));
998 
999  erow->set_clock_group (*_clock_group);
1000  erow->remove_requested.connect (sigc::mem_fun(*this, &LocationUI::location_remove_requested));
1001 
1002  Box_Helpers::BoxList & range_children = range_rows.children();
1003  range_children.push_back(Box_Helpers::Element(*erow, PACK_SHRINK, 1, PACK_START));
1004  }
1005  }
1006 
1007  range_rows.show_all();
1008  location_rows.show_all();
1009 }
1010 
1011 void
1013 {
1014  string markername;
1015 
1016  if (_session) {
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;
1022  }
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));
1029  }
1030 
1031 }
1032 
1033 void
1035 {
1036  string rangename;
1037 
1038  if (_session) {
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));
1048  }
1049 }
1050 
1051 void
1053 {
1055  using namespace Box_Helpers;
1056 
1057  // this is just too expensive to do when window is not shown
1058  if (!is_mapped()) {
1059  return;
1060  }
1061 
1062  BoxList & loc_children = location_rows.children();
1063  BoxList & range_children = range_rows.children();
1064 
1065  loc_children.clear();
1066  range_children.clear();
1067 
1068  if (_session) {
1070  }
1071 }
1072 
1073 void
1075 {
1076  SessionHandlePtr::set_session (s);
1077 
1078  if (_session) {
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());
1082 
1084  }
1085 
1088 
1090 }
1091 
1092 void
1094 {
1096 
1097  using namespace Box_Helpers;
1098  BoxList & loc_children = location_rows.children();
1099  BoxList & range_children = range_rows.children();
1100 
1101  loc_children.clear();
1102  range_children.clear();
1103 
1106 
1109 
1110  SessionHandlePtr::session_going_away ();
1111 }
1112 
1113 XMLNode &
1115 {
1116  XMLNode* node = new XMLNode (X_("LocationUI"));
1117  node->add_property (X_("clock-mode"), enum_2_string (_clock_group->clock_mode ()));
1118  return *node;
1119 }
1120 
1123 {
1124  XMLNode* node = _session->instant_xml (X_("LocationUI"));
1125  if (!node) {
1126  return AudioClock::Frames;
1127  }
1128 
1129  XMLProperty* p = node->property (X_("clock-mode"));
1130  if (!p) {
1132  }
1133 
1135 }
1136 
1137 
1138 /*------------------------*/
1139 
1141  : ArdourWindow (_("Locations"))
1142 {
1143  set_wmclass(X_("ardour_locations"), PROGRAM_NAME);
1144  set_name ("LocationWindow");
1145 
1146  add (_ui);
1147 }
1148 
1150 {
1151 }
1152 
1153 void
1155 {
1156  ArdourWindow::on_map ();
1158 }
1159 
1160 bool
1162 {
1163  return false;
1164 }
1165 
1166 void
1168 {
1170  _ui.set_session (s);
1171  _ui.show_all ();
1172 }
1173 
1174 void
1176 {
1178  hide_all();
1179 }
int next_available_name(std::string &result, std::string base)
Definition: location.cc:797
framepos_t audible_frame() const
Definition: session.cc:1760
framepos_t current_time(framepos_t position=0) const
ARDOUR::Location * get_location()
Definition: location_ui.h:53
AudioClock::Mode clock_mode_from_session_instant_xml() const
Gtk::CheckButton preemph_check_button
Definition: location_ui.h:108
void set_session(ARDOUR::Session *)
void add_new_range()
void set_clock_group(ClockGroup &)
Definition: location_ui.cc:185
void set(framepos_t, bool force=false, ARDOUR::framecnt_t offset=0)
Definition: audio_clock.cc:956
Gtk::VBox range_frame_box
Definition: location_ui.h:184
Gtk::VBox loc_frame_box
Definition: location_ui.h:179
virtual void session_going_away()
Gtk::CheckButton glue_check_button
Definition: location_ui.h:93
Gtk::VBox loop_punch_box
Definition: location_ui.h:175
const std::string & value() const
Definition: xml++.h:159
void set_session(ARDOUR::Session *s)
std::list< Location * > LocationList
Definition: location.h:167
PBD::Signal1< void, Location * > added
Definition: location.h:209
Gtk::VBox range_rows
Definition: location_ui.h:187
gint do_location_remove(ARDOUR::Location *)
Definition: location_ui.cc:848
void name_entry_changed()
Definition: location_ui.cc:352
Gtk::VPaned loc_range_panes
Definition: location_ui.h:177
Gtk::HBox end_hbox
Definition: location_ui.h:85
Gtk::CheckButton hide_check_button
Definition: location_ui.h:91
#define enum_2_string(e)
Definition: enumwriter.h:97
void set_name(const std::string &str)
Definition: location.cc:167
Definition: ardour_ui.h:130
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
PBD::Signal0< void > LockChanged
Definition: location.h:131
void start_changed()
Definition: location_ui.cc:611
void add_command(Command *const cmd)
Definition: session.h:787
guint32 i_am_the_modifier
Definition: location_ui.h:112
LocationUI _ui
Definition: location_ui.h:222
bool operator()(Location *a, Location *b)
Definition: location_ui.cc:887
Gtk::Label composer_label
Definition: location_ui.h:104
framepos_t end() const
Definition: location.h:72
Gtk::ScrolledWindow location_rows_scroller
Definition: location_ui.h:181
Definition: Beats.hpp:239
LIBPBD_API Transmitter error
virtual ~LocationEditRow()
Definition: location_ui.cc:171
std::ostream & endmsg(std::ostream &ostr)
Definition: transmitter.h:71
bool is_cd_marker() const
Definition: location.h:96
void request_locate(framepos_t frame, bool with_roll=false)
Gtk::Button add_range_button
Definition: location_ui.h:185
void add_new_location()
bool is_hidden() const
Definition: location.h:95
#define ENSURE_GUI_THREAD(obj, method,...)
Definition: gui_thread.h:34
guint32 i_am_the_modifier
Definition: location_ui.h:200
ClockGroup * _clock_group
Definition: location_ui.h:110
#define invalidator(x)
Definition: gui_thread.h:40
bool is_session_range() const
Definition: location.h:97
Gtk::VBox location_rows
Definition: location_ui.h:182
void location_changed()
Definition: location_ui.cc:645
MainClock * secondary_clock
Definition: ardour_ui.h:230
void isrc_entry_changed()
Definition: location_ui.cc:365
Locations * locations()
Definition: session.h:382
PBD::ScopedConnectionList connections
Definition: location_ui.h:145
void composer_entry_changed()
Definition: location_ui.cc:395
void session_going_away()
#define _(Text)
Definition: i18n.h:11
Gtk::HBox cd_track_details_hbox
Definition: location_ui.h:97
PositionLockStyle position_lock_style() const
Definition: location.h:142
#define X_(Text)
Definition: i18n.h:13
XMLNode & get_state() const
AudioClock length_clock
Definition: location_ui.h:89
XMLProperty * property(const char *)
Definition: xml++.cc:413
PBD::Signal0< void > PositionLockStyleChanged
Definition: location.h:132
void flags_changed()
Definition: location_ui.cc:663
#define string_2_enum(str, e)
Definition: enumwriter.h:98
Mode mode() const
Definition: audio_clock.h:56
void unset_clock_group()
Definition: location_ui.h:60
std::map< std::string, std::string > cd_info
Definition: location.h:136
bool is_auto_punch() const
Definition: location.h:92
void set_clock_editable_status()
Definition: location_ui.cc:715
PBD::Signal1< void, Location * > removed
Definition: location.h:210
PBD::Signal0< void > FlagsChanged
Definition: location.h:130
const LocationList & list()
Definition: location.h:172
Gtk::Button start_to_playhead_button
Definition: location_ui.h:83
void set_session(ARDOUR::Session *)
Definition: location_ui.cc:201
Gtk::Label scms_label
Definition: location_ui.h:107
framepos_t transport_frame() const
Definition: session.h:551
Definition: amp.h:29
Gtk::Entry isrc_entry
Definition: location_ui.h:98
void session_going_away()
LocationEditRow punch_edit_row
Definition: location_ui.h:174
bool locked() const
Definition: location.h:67
Gtk::CheckButton scms_check_button
Definition: location_ui.h:106
void show_cd_track_details()
Definition: location_ui.cc:459
virtual void begin_reversible_command(std::string cmd_name)=0
#define gui_context()
Definition: gui_thread.h:36
sigc::signal< void > redraw_ranges
Definition: location_ui.h:63
virtual void commit_reversible_command()=0
bool on_delete_event(GdkEventAny *)
void refresh_location_list()
void clock_changed(LocationPart part)
Definition: location_ui.cc:438
Flags flags() const
Definition: location.h:103
int64_t framepos_t
Definition: types.h:66
Gtk::Label performer_label
Definition: location_ui.h:102
void map_locations(const ARDOUR::Locations::LocationList &)
Definition: location_ui.cc:965
Gtk::Tooltips & tooltips()
Definition: ardour_ui.h:199
PBD::Signal0< void > NameChanged
Definition: location.h:126
PBD::ScopedConnectionList _session_connections
LocationEditRow(ARDOUR::Session *sess=0, ARDOUR::Location *loc=0, int32_t num=-1)
Definition: location_ui.cc:47
AudioClock end_clock
Definition: location_ui.h:86
Gtk::Table item_table
Definition: location_ui.h:75
sigc::signal< void > ValueChanged
Definition: audio_clock.h:92
bool is_mark() const
Definition: location.h:94
void set_tip(Gtk::Widget &w, const gchar *tip)
int set_start(framepos_t s, bool force=false, bool allow_bbt_recompute=true)
Definition: location.cc:181
void set_location(ARDOUR::Location *)
Definition: location_ui.cc:225
XMLProperty * add_property(const char *name, const std::string &value)
void performer_entry_changed()
Definition: location_ui.cc:381
void add(Location *, bool make_current=false)
Definition: location.cc:953
static PublicEditor & instance()
Gtk::Button add_location_button
Definition: location_ui.h:180
AudioClock start_clock
Definition: location_ui.h:82
Gtk::Entry name_entry
Definition: location_ui.h:77
Gtk::Entry performer_entry
Definition: location_ui.h:103
XMLNode & get_state(void)
Definition: location.cc:1017
Gtk::Label isrc_label
Definition: location_ui.h:99
ClockGroup * _clock_group
Definition: location_ui.h:206
const std::string & name() const
Definition: location.h:81
void set_cd(bool yn, void *src)
Definition: location.cc:450
void location_added(ARDOUR::Location *)
Definition: location_ui.cc:893
void remove(AudioClock &)
Definition: clock_group.cc:42
XMLNode * instant_xml(const std::string &str)
framepos_t current_start_frame() const
Definition: session.cc:5042
Definition: xml++.h:95
static UIConfiguration * config()
Definition: ardour_ui.h:188
void location_redraw_ranges()
Definition: location_ui.cc:880
ARDOUR::Location * location
Definition: location_ui.h:73
LocationEditRow loop_edit_row
Definition: location_ui.h:173
Definition: debug.h:30
framecnt_t length() const
Definition: location.h:73
PBD::Signal0< void > EndChanged
Definition: location.h:127
sigc::signal< void, ARDOUR::Location * > remove_requested
Definition: location_ui.h:62
void set_number(int)
Definition: location_ui.cc:215
framepos_t current_duration(framepos_t position=0) const
PBD::Signal0< void > StartChanged
Definition: location.h:128
Gtk::Entry composer_entry
Definition: location_ui.h:105
framepos_t start() const
Definition: location.h:71
void add(AudioClock &)
Definition: clock_group.cc:33
void location_removed(ARDOUR::Location *)
Definition: location_ui.cc:944
void remove(Location *)
Definition: location.cc:979
AudioClock::Mode clock_mode() const
Definition: clock_group.h:34
bool is_range_marker() const
Definition: location.h:98
virtual void set_session(ARDOUR::Session *)
void position_lock_style_changed()
Definition: location_ui.cc:695
Gtk::CheckButton cd_check_button
Definition: location_ui.h:90
Gtk::Label number_label
Definition: location_ui.h:79
Gtk::HBox start_hbox
Definition: location_ui.h:81
bool locate_to_clock(GdkEventButton *, AudioClock *)
Definition: location_ui.cc:428
Gtk::Button remove_button
Definition: location_ui.h:95
void preemph_toggled()
Definition: location_ui.cc:583
bool is_auto_loop() const
Definition: location.h:93
Gtk::ScrolledWindow range_rows_scroller
Definition: location_ui.h:186
Gtk::Label preemph_label
Definition: location_ui.h:109
void apply(T &obj, void(T::*method)(const LocationList &)) const
Definition: location.h:213
void to_playhead_button_pressed(LocationPart part)
Definition: location_ui.cc:409
Gtk::Label name_label
Definition: location_ui.h:78
void set_editable(bool yn)
void set_hidden(bool yn, void *src)
Definition: location.cc:441
ARDOUR::Session * _session
void set_session(ARDOUR::Session *)
void location_remove_requested(ARDOUR::Location *)
Definition: location_ui.cc:870
PBD::Signal0< void > changed
Definition: location.h:211
int set_end(framepos_t e, bool force=false, bool allow_bbt_recompute=true)
Definition: location.cc:258
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
ARDOUR::Location * newest_location
Definition: location_ui.h:169
PBD::Signal0< void > Changed
Definition: location.h:129
Gtk::Button end_to_playhead_button
Definition: location_ui.h:87
void remove_button_pressed()
Definition: location_ui.cc:558
Gtk::CheckButton lock_check_button
Definition: location_ui.h:92
void set_position_lock_style(PositionLockStyle ps)
Definition: location.cc:700
void set_clock_mode(AudioClock::Mode)
Definition: clock_group.cc:56