changes from colin for route_params, nick for location_ui and route_ui, and me for...
[ardour.git] / gtk2_ardour / location_ui.cc
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     $Id$
19 */
20
21 #include <cmath>
22 #include <cstdlib>
23
24 #include <gtkmm2ext/utils.h>
25 #include <gtkmm2ext/stop_signal.h>
26
27 #include <ardour/utils.h>
28 #include <ardour/configuration.h>
29 #include <ardour/session.h>
30
31 #include "ardour_ui.h"
32 #include "prompter.h"
33 #include "location_ui.h"
34 #include "keyboard.h"
35 #include "utils.h"
36 #include "gui_thread.h"
37
38 #include "i18n.h"
39
40 using namespace ARDOUR;
41 using namespace Gtk;
42 using namespace Gtkmm2ext;
43
44 LocationEditRow::LocationEditRow(Session * sess, Location * loc, int32_t num)
45         : location(0), session(0),
46           item_table (1, 7, false),
47           start_set_button (_("Set")),
48           start_go_button (_("Go")),
49           start_clock (X_("LocationEditRowClock"), true),
50           end_set_button (_("Set")),
51           end_go_button (_("Go")),
52           end_clock (X_("LocationEditRowClock"), true),
53           length_clock (X_("LocationEditRowClock"), true, true),
54           cd_check_button (_("CD")),
55           hide_check_button (_("Hidden")),
56           remove_button (_("Remove")),
57           scms_check_button (_("SCMS")),
58           preemph_check_button (_("Pre-Emphasis"))
59
60 {
61         
62         i_am_the_modifier = 0;
63
64         number_label.set_name ("LocationEditNumberLabel");
65         name_label.set_name ("LocationEditNameLabel");
66         name_entry.set_name ("LocationEditNameEntry");
67         start_set_button.set_name ("LocationEditSetButton");
68         start_go_button.set_name ("LocationEditGoButton");
69         end_set_button.set_name ("LocationEditSetButton");
70         end_go_button.set_name ("LocationEditGoButton");
71         cd_check_button.set_name ("LocationEditCdButton");
72         hide_check_button.set_name ("LocationEditHideButton");
73         remove_button.set_name ("LocationEditRemoveButton");
74         isrc_label.set_name ("LocationEditNumberLabel");
75         isrc_entry.set_name ("LocationEditNameEntry");
76         scms_check_button.set_name ("LocationEditCdButton");
77         preemph_check_button.set_name ("LocationEditCdButton");
78         performer_label.set_name ("LocationEditNumberLabel");
79         performer_entry.set_name ("LocationEditNameEntry");
80         composer_label.set_name ("LocationEditNumberLabel");
81         composer_entry.set_name ("LocationEditNameEntry");
82
83
84         isrc_label.set_text ("ISRC: ");
85         isrc_label.set_size_request (30, -1);
86         performer_label.set_text ("Performer: ");
87         performer_label.set_size_request (60, -1);
88         composer_label.set_text ("Composer: ");
89         composer_label.set_size_request (60, -1);
90
91         isrc_entry.set_size_request (112, -1);
92         isrc_entry.set_max_length(12);
93         isrc_entry.set_editable (true);
94
95         performer_entry.set_size_request (100, -1);
96         performer_entry.set_editable (true);
97
98         composer_entry.set_size_request (100, -1);
99         composer_entry.set_editable (true);
100
101         cd_track_details_hbox.pack_start (isrc_label, false, false);
102         cd_track_details_hbox.pack_start (isrc_entry, false, false);
103         cd_track_details_hbox.pack_start (scms_check_button, false, false);
104         cd_track_details_hbox.pack_start (preemph_check_button, false, false);
105         cd_track_details_hbox.pack_start (performer_label, false, false);
106         cd_track_details_hbox.pack_start (performer_entry, true, true);
107         cd_track_details_hbox.pack_start (composer_label, false, false);
108         cd_track_details_hbox.pack_start (composer_entry, true, true);
109
110         isrc_entry.signal_changed().connect (mem_fun(*this, &LocationEditRow::isrc_entry_changed)); 
111         isrc_entry.signal_focus_in_event().connect (mem_fun(*this, &LocationEditRow::entry_focus_event));
112         isrc_entry.signal_focus_out_event().connect (mem_fun(*this, &LocationEditRow::entry_focus_event));
113
114         performer_entry.signal_changed().connect (mem_fun(*this, &LocationEditRow::performer_entry_changed));
115         performer_entry.signal_focus_in_event().connect (mem_fun(*this, &LocationEditRow::entry_focus_event));
116         performer_entry.signal_focus_out_event().connect (mem_fun(*this, &LocationEditRow::entry_focus_event));
117
118         composer_entry.signal_changed().connect (mem_fun(*this, &LocationEditRow::composer_entry_changed));
119         composer_entry.signal_focus_in_event().connect (mem_fun(*this, &LocationEditRow::entry_focus_event));
120         composer_entry.signal_focus_out_event().connect (mem_fun(*this, &LocationEditRow::entry_focus_event));
121
122         scms_check_button.signal_toggled().connect(mem_fun(*this, &LocationEditRow::scms_toggled));
123         preemph_check_button.signal_toggled().connect(mem_fun(*this, &LocationEditRow::preemph_toggled));
124
125
126         set_session (sess);
127
128
129         item_table.attach (number_label, 0, 1, 0, 1, FILL, FILL, 3, 0);
130         
131         start_hbox.pack_start (start_go_button, false, false);
132         start_hbox.pack_start (start_clock, false, false);
133         start_hbox.pack_start (start_set_button, false, false);
134
135         item_table.attach (start_hbox, 2, 3, 0, 1, FILL, FILL, 4, 0);
136
137         
138         start_set_button.signal_clicked().connect(bind (mem_fun (*this, &LocationEditRow::set_button_pressed), LocStart));
139         start_go_button.signal_clicked().connect(bind (mem_fun (*this, &LocationEditRow::go_button_pressed), LocStart));
140         start_clock.ValueChanged.connect (bind (mem_fun (*this, &LocationEditRow::clock_changed), LocStart));
141
142         
143         end_hbox.pack_start (end_go_button, false, false);
144         end_hbox.pack_start (end_clock, false, false);
145         end_hbox.pack_start (end_set_button, false, false);
146         
147         //item_table.attach (end_hbox, 2, 3, 0, 1, 0, 0, 4, 0);
148         
149         end_set_button.signal_clicked().connect(bind (mem_fun (*this, &LocationEditRow::set_button_pressed), LocEnd));
150         end_go_button.signal_clicked().connect(bind (mem_fun (*this, &LocationEditRow::go_button_pressed), LocEnd));
151         end_clock.ValueChanged.connect (bind (mem_fun (*this, &LocationEditRow::clock_changed), LocEnd));
152         
153 //      item_table.attach (length_clock, 3, 4, 0, 1, 0, 0, 4, 0);
154         length_clock.ValueChanged.connect (bind ( mem_fun(*this, &LocationEditRow::clock_changed), LocLength));
155
156 //      item_table.attach (cd_check_button, 4, 5, 0, 1, 0, Gtk::FILL, 4, 0);
157 //      item_table.attach (hide_check_button, 5, 6, 0, 1, 0, Gtk::FILL, 4, 0);
158 //      item_table.attach (remove_button, 7, 8, 0, 1, 0, Gtk::FILL, 4, 0);
159         
160         cd_check_button.signal_toggled().connect(mem_fun(*this, &LocationEditRow::cd_toggled));
161         hide_check_button.signal_toggled().connect(mem_fun(*this, &LocationEditRow::hide_toggled));
162         
163         remove_button.signal_clicked().connect(mem_fun(*this, &LocationEditRow::remove_button_pressed));
164
165         pack_start(item_table, true, true);
166
167         set_location (loc);
168         set_number (num);
169 }
170
171 LocationEditRow::~LocationEditRow()
172 {
173         if (location) {
174                 start_changed_connection.disconnect();
175                 end_changed_connection.disconnect();
176                 name_changed_connection.disconnect();
177                 changed_connection.disconnect();
178                 flags_changed_connection.disconnect();
179         }
180 }
181
182 void
183 LocationEditRow::set_session (Session *sess)
184 {
185         session = sess;
186
187         if (!session) return;
188
189         start_clock.set_session (session);
190         end_clock.set_session (session);
191         length_clock.set_session (session);     
192         
193 }
194
195 void
196 LocationEditRow::set_number (int num)
197 {
198         number = num;
199
200         if (number >= 0 ) {
201                 number_label.set_text (compose ("%1", number));
202         }
203 }
204
205 void
206 LocationEditRow::set_location (Location *loc)
207 {
208         if (location) {
209                 start_changed_connection.disconnect();
210                 end_changed_connection.disconnect();
211                 name_changed_connection.disconnect();
212                 changed_connection.disconnect();
213                 flags_changed_connection.disconnect();
214         }
215
216         location = loc;
217
218         if (!location) return;
219
220         if (!hide_check_button.get_parent()) {
221                 item_table.attach (hide_check_button, 6, 7, 0, 1, FILL, Gtk::FILL, 4, 0);
222         }
223         hide_check_button.set_active (location->is_hidden());
224         
225         if (location->is_auto_loop() || location->is_auto_punch()) {
226                 // use label instead of entry
227
228                 name_label.set_text (location->name());
229                 name_label.set_size_request (80, -1);
230
231                 if (!name_label.get_parent()) {
232                         item_table.attach (name_label, 1, 2, 0, 1, FILL, Gtk::FILL, 4, 0);
233                 }
234                 
235                 name_label.show();
236
237         } else {
238
239                 name_entry.set_text (location->name());
240                 name_entry.set_size_request (100, -1);
241                 name_entry.set_editable (true);
242                 name_entry.signal_changed().connect (mem_fun(*this, &LocationEditRow::name_entry_changed));  
243                 name_entry.signal_focus_in_event().connect (mem_fun(*this, &LocationEditRow::entry_focus_event));
244                 name_entry.signal_focus_out_event().connect (mem_fun(*this, &LocationEditRow::entry_focus_event));
245
246                 if (!name_entry.get_parent()) {
247                         item_table.attach (name_entry, 1, 2, 0, 1, FILL | EXPAND, FILL, 4, 0);
248                 }
249                 name_entry.show();
250
251                 if (!cd_check_button.get_parent()) {
252                         item_table.attach (cd_check_button, 5, 6, 0, 1, FILL, Gtk::FILL, 4, 0);
253                 }
254                 if (!remove_button.get_parent()) {
255                         item_table.attach (remove_button, 7, 8, 0, 1, FILL, Gtk::FILL, 4, 0);
256                 }
257
258                 /* XXX i can't find a way to hide the button without messing up 
259                    the row spacing, so make it insensitive (paul).
260                 */
261
262                 if (location->is_end()) {
263                         remove_button.set_sensitive (false);
264                 }
265
266                 cd_check_button.set_active (location->is_cd_marker());
267                 cd_check_button.show();
268                 hide_check_button.show();
269         }
270
271         start_clock.set (location->start(), true);
272         
273
274         if (!location->is_mark()) {
275                 if (!end_hbox.get_parent()) {
276                         item_table.attach (end_hbox, 3, 4, 0, 1, FILL, FILL, 4, 0);
277                 }
278                 if (!length_clock.get_parent()) {
279                         item_table.attach (length_clock, 4, 5, 0, 1, FILL, FILL, 4, 0);
280                 }
281
282                 end_clock.set (location->end(), true);
283                 length_clock.set (location->length(), true);
284
285                 end_set_button.show();
286                 end_go_button.show();
287                 end_clock.show();
288                 length_clock.show();
289         }
290         else {
291                 end_set_button.hide();
292                 end_go_button.hide();
293                 end_clock.hide();
294                 length_clock.hide();
295         }
296
297         start_changed_connection = location->start_changed.connect (mem_fun(*this, &LocationEditRow::start_changed));
298         end_changed_connection = location->end_changed.connect (mem_fun(*this, &LocationEditRow::end_changed));
299         name_changed_connection = location->name_changed.connect (mem_fun(*this, &LocationEditRow::name_changed));
300         changed_connection = location->changed.connect (mem_fun(*this, &LocationEditRow::location_changed));
301         flags_changed_connection = location->FlagsChanged.connect (mem_fun(*this, &LocationEditRow::flags_changed));
302         
303 }
304
305 gint
306 LocationEditRow::entry_focus_event (GdkEventFocus* ev)
307 {
308         if (ev->in) {
309                 ARDOUR_UI::instance()->allow_focus (true);
310         } else {
311                 ARDOUR_UI::instance()->allow_focus (false);
312         }
313         return TRUE;
314 }
315
316
317 void
318 LocationEditRow::name_entry_changed ()
319 {
320         ENSURE_GUI_THREAD(mem_fun(*this, &LocationEditRow::name_entry_changed));
321         if (i_am_the_modifier || !location) return;
322
323         location->set_name (name_entry.get_text());
324 }
325
326
327 void
328 LocationEditRow::isrc_entry_changed ()
329 {
330         ENSURE_GUI_THREAD(mem_fun(*this, &LocationEditRow::isrc_entry_changed));
331         
332         if (i_am_the_modifier || !location) return;
333
334         if (isrc_entry.get_text() != "" ) {
335
336           location->cd_info["isrc"] = isrc_entry.get_text();
337           
338         } else {
339           location->cd_info.erase("isrc");
340         }
341 }
342
343 void
344 LocationEditRow::performer_entry_changed ()
345 {
346         ENSURE_GUI_THREAD(mem_fun(*this, &LocationEditRow::performer_entry_changed));
347         
348         if (i_am_the_modifier || !location) return;
349
350         if (performer_entry.get_text() != "") {
351           location->cd_info["performer"] = performer_entry.get_text();
352         } else {
353           location->cd_info.erase("performer");
354         }
355 }
356
357 void
358 LocationEditRow::composer_entry_changed ()
359 {
360         ENSURE_GUI_THREAD(mem_fun(*this, &LocationEditRow::composer_entry_changed));
361         
362         if (i_am_the_modifier || !location) return;
363
364         if (composer_entry.get_text() != "") {
365         location->cd_info["composer"] = composer_entry.get_text();
366         } else {
367           location->cd_info.erase("composer");
368         }
369 }
370
371
372 void
373 LocationEditRow::set_button_pressed (LocationPart part)
374 {
375         if (!location) return;
376         
377         switch (part) {
378         case LocStart:
379                 location->set_start (session->transport_frame ());
380                 break;
381         case LocEnd:
382                 location->set_end (session->transport_frame ());
383                 break;
384         default:
385                 break;
386         }
387 }
388
389 void
390 LocationEditRow::go_button_pressed (LocationPart part)
391 {
392         if (!location) return;
393
394         switch (part) {
395         case LocStart:
396                 ARDOUR_UI::instance()->do_transport_locate (location->start());
397                 break;
398         case LocEnd:
399                 ARDOUR_UI::instance()->do_transport_locate (location->end());
400                 break;
401         default:
402                 break;
403         }
404 }
405
406 void
407 LocationEditRow::clock_changed (LocationPart part)
408 {
409         if (i_am_the_modifier || !location) return;
410         
411         switch (part) {
412         case LocStart:
413                 location->set_start (start_clock.current_time());
414                 break;
415         case LocEnd:
416                 location->set_end (end_clock.current_time());
417                 break;
418         case LocLength:
419                 location->set_end (location->start() + length_clock.current_duration());
420         default:
421                 break;
422         }
423
424 }
425
426 void
427 LocationEditRow::cd_toggled ()
428 {
429
430         if (i_am_the_modifier || !location) return;
431         location->set_cd (cd_check_button.get_active(), this);
432
433         if (location->is_cd_marker() && !(location->is_mark())) {
434
435           if (location->cd_info.find("isrc") != location->cd_info.end()) {
436             isrc_entry.set_text(location->cd_info["isrc"]);
437           }
438           if (location->cd_info.find("performer") != location->cd_info.end()) {
439             performer_entry.set_text(location->cd_info["performer"]);
440           }
441           if (location->cd_info.find("composer") != location->cd_info.end()) {
442             composer_entry.set_text(location->cd_info["composer"]);
443           }
444           if (location->cd_info.find("scms") != location->cd_info.end()) {
445             scms_check_button.set_active(true);
446           }
447           if (location->cd_info.find("preemph") != location->cd_info.end()) {
448             preemph_check_button.set_active(true);
449           }
450           
451           if(!cd_track_details_hbox.get_parent()) {
452             item_table.attach (cd_track_details_hbox, 1, 8, 1, 2, FILL | EXPAND, FILL, 4, 0);
453           }
454           // item_table.resize(2, 7);
455           cd_track_details_hbox.show_all();
456
457         } else if (cd_track_details_hbox.get_parent()){
458
459             item_table.remove (cd_track_details_hbox);  
460             //    item_table.resize(1, 7);
461             redraw_ranges(); /*         EMIT_SIGNAL */
462         }
463
464 }
465
466
467 void
468 LocationEditRow::hide_toggled ()
469 {
470         if (i_am_the_modifier || !location) return;
471
472         location->set_hidden (hide_check_button.get_active(), this);
473 }
474
475 void
476 LocationEditRow::remove_button_pressed ()
477 {
478         if (!location) return;
479
480         remove_requested(location); /*  EMIT_SIGNAL */
481 }
482
483
484
485 void
486 LocationEditRow::scms_toggled ()
487 {
488         if (i_am_the_modifier || !location) return;
489
490         if (scms_check_button.get_active()) {
491           location->cd_info["scms"] = "on";
492         } else {
493           location->cd_info.erase("scms");
494         }
495         
496 }
497
498 void
499 LocationEditRow::preemph_toggled ()
500 {
501         if (i_am_the_modifier || !location) return;
502
503         if (preemph_check_button.get_active()) {
504           location->cd_info["preemph"] = "on";
505         } else {
506           location->cd_info.erase("preemph");
507         }
508 }
509
510 void
511 LocationEditRow::end_changed (ARDOUR::Location *loc)
512 {
513         ENSURE_GUI_THREAD(bind (mem_fun(*this, &LocationEditRow::end_changed), loc));
514
515         if (!location) return;
516                 
517         // update end and length
518         i_am_the_modifier++;
519
520         end_clock.set (location->end());
521         length_clock.set (location->length());
522         
523         i_am_the_modifier--;
524 }
525
526 void
527 LocationEditRow::start_changed (ARDOUR::Location *loc)
528 {
529         ENSURE_GUI_THREAD(bind (mem_fun(*this, &LocationEditRow::start_changed), loc));
530         
531         if (!location) return;
532         
533         // update end and length
534         i_am_the_modifier++;
535
536         start_clock.set (location->start());
537         
538         i_am_the_modifier--;
539 }
540
541 void
542 LocationEditRow::name_changed (ARDOUR::Location *loc)
543 {
544         ENSURE_GUI_THREAD(bind (mem_fun(*this, &LocationEditRow::name_changed), loc));
545         
546         if (!location) return;
547
548         // update end and length
549         i_am_the_modifier++;
550
551         name_entry.set_text(location->name());
552         name_label.set_text(location->name());
553
554         i_am_the_modifier--;
555
556 }
557
558 void
559 LocationEditRow::location_changed (ARDOUR::Location *loc)
560 {       
561         ENSURE_GUI_THREAD(bind (mem_fun(*this, &LocationEditRow::location_changed), loc));
562         
563         if (!location) return;
564
565         i_am_the_modifier++;
566
567         start_clock.set (location->start());
568         end_clock.set (location->end());
569         length_clock.set (location->length());
570
571         i_am_the_modifier--;
572
573 }
574
575 void
576 LocationEditRow::flags_changed (ARDOUR::Location *loc, void *src)
577 {
578         ENSURE_GUI_THREAD(bind (mem_fun(*this, &LocationEditRow::flags_changed), loc, src));
579         
580         if (!location) return;
581
582         i_am_the_modifier++;
583
584         cd_check_button.set_active (location->is_cd_marker());
585         hide_check_button.set_active (location->is_hidden());
586
587         i_am_the_modifier--;
588 }
589
590 LocationUI::LocationUI ()
591         : ArdourDialog ("location dialog"),
592           add_location_button (_("Add New Location")),
593           add_range_button (_("Add New Range"))
594 {
595         i_am_the_modifier = 0;
596
597         set_title(_("ardour: locations"));
598         set_wmclass(_("ardour_locations"), "Ardour");
599
600         set_name ("LocationWindow");
601         signal_delete_event().connect (bind (ptr_fun (just_hide_it), static_cast<Window*>(this)));
602
603         add (location_hpacker);
604
605
606         location_vpacker.set_border_width (10);
607         location_vpacker.set_spacing (5);
608
609
610         location_vpacker.pack_start (loop_edit_row, false, false);
611         location_vpacker.pack_start (punch_edit_row, false, false);
612
613         location_rows.set_name("LocationLocRows");
614         location_rows_scroller.add_with_viewport (location_rows);
615         location_rows_scroller.set_name ("LocationLocRowsScroller");
616         location_rows_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
617         location_rows_scroller.set_size_request (-1, 130);
618
619         loc_frame_box.set_spacing (5);
620         loc_frame_box.set_border_width (5);
621         loc_frame_box.set_name("LocationFrameBox");
622         
623         loc_frame_box.pack_start (location_rows_scroller, true, true);
624
625         add_location_button.set_name ("LocationAddLocationButton");
626         loc_frame_box.pack_start (add_location_button, false, false);
627
628         loc_frame.set_name ("LocationLocEditorFrame");
629         loc_frame.set_label (_("Location (CD Index) Markers"));
630         loc_frame.add (loc_frame_box);
631         loc_range_panes.pack1(loc_frame, true, false);
632
633         
634         range_rows.set_name("LocationRangeRows");
635         range_rows_scroller.add_with_viewport (range_rows);
636         range_rows_scroller.set_name ("LocationRangeRowsScroller");
637         range_rows_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
638         range_rows_scroller.set_size_request (-1, 130);
639         
640         range_frame_box.set_spacing (5);
641         range_frame_box.set_name("LocationFrameBox");
642         range_frame_box.set_border_width (5);
643         range_frame_box.pack_start (range_rows_scroller, true, true);
644
645         add_range_button.set_name ("LocationAddRangeButton");
646         range_frame_box.pack_start (add_range_button, false, false);
647
648         range_frame.set_name ("LocationRangeEditorFrame");
649         range_frame.set_label (_("Range (CD Track) Markers"));
650         range_frame.add (range_frame_box);
651         loc_range_panes.pack2(range_frame, true, false);
652         location_vpacker.pack_start (loc_range_panes, true, true);
653         
654         location_hpacker.pack_start (location_vpacker, true, true);
655
656         add_location_button.signal_clicked().connect (mem_fun(*this, &LocationUI::add_new_location));
657         add_range_button.signal_clicked().connect (mem_fun(*this, &LocationUI::add_new_range));
658         
659         //add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::BUTTON_RELEASE_MASK);
660
661         
662 }
663
664 LocationUI::~LocationUI()
665 {
666 }
667
668
669
670 gint LocationUI::do_location_remove (ARDOUR::Location *loc)
671 {
672         /* this is handled internally by Locations, but there's
673            no point saving state etc. when we know the marker
674            cannot be removed.
675         */
676
677         if (loc->is_end()) {
678                 return FALSE;
679         }
680
681         session->begin_reversible_command (_("remove marker"));
682         session->add_undo (session->locations()->get_memento());
683         session->locations()->remove (loc);
684         session->add_redo_no_execute (session->locations()->get_memento());
685         session->commit_reversible_command ();
686
687         return FALSE;
688 }
689
690 void LocationUI::location_remove_requested (ARDOUR::Location *loc)
691 {
692         // must do this to prevent problems when destroying
693         // the effective sender of this event
694         
695   Glib::signal_idle().connect (bind (mem_fun(*this, &LocationUI::do_location_remove), loc));
696 }
697
698
699 void LocationUI::location_redraw_ranges ()
700 {
701
702         range_rows.hide();
703         range_rows.show();
704
705 }
706
707
708 void
709 LocationUI::location_added (Location* location)
710 {
711         ENSURE_GUI_THREAD(bind (mem_fun(*this, &LocationUI::location_added), location));
712         
713         if (location->is_auto_punch()) {
714                 punch_edit_row.set_location(location);
715         }
716         else if (location->is_auto_loop()) {
717                 loop_edit_row.set_location(location);
718         }
719         else {
720                 refresh_location_list ();
721         }
722 }
723
724 void
725 LocationUI::location_removed (Location* location)
726 {
727         ENSURE_GUI_THREAD(bind (mem_fun(*this, &LocationUI::location_removed), location));
728         
729         if (location->is_auto_punch()) {
730                 punch_edit_row.set_location(0);
731         }
732         else if (location->is_auto_loop()) {
733                 loop_edit_row.set_location(0);
734         }
735         else {
736                 refresh_location_list ();
737         }
738 }
739
740 struct LocationSortByStart {
741     bool operator() (Location *a, Location *b) {
742             return a->start() < b->start();
743     }
744 };
745
746 void
747 LocationUI::map_locations (Locations::LocationList& locations)
748 {
749         Locations::LocationList::iterator i;
750         Location* location;
751         gint n; 
752         int mark_n = 0;
753         Locations::LocationList temp = locations;
754         LocationSortByStart cmp;
755
756         temp.sort (cmp);
757         locations = temp;
758
759         Box_Helpers::BoxList & loc_children = location_rows.children();
760         Box_Helpers::BoxList & range_children = range_rows.children();
761         LocationEditRow * erow;
762         
763         for (n = 0, i = locations.begin(); i != locations.end(); ++n, ++i) {
764
765                 location = *i;
766
767                 if (location->is_mark()) {
768                         mark_n++;
769                         erow = manage (new LocationEditRow(session, location, mark_n));
770                         erow->remove_requested.connect (mem_fun(*this, &LocationUI::location_remove_requested));
771                         erow->redraw_ranges.connect (mem_fun(*this, &LocationUI::location_redraw_ranges));
772                         loc_children.push_back(Box_Helpers::Element(*erow, PACK_SHRINK, 1, PACK_START));
773                 }
774                 else if (location->is_auto_punch()) {
775                         punch_edit_row.set_session (session);
776                         punch_edit_row.set_location (location);
777                 }
778                 else if (location->is_auto_loop()) {
779                         loop_edit_row.set_session (session);
780                         loop_edit_row.set_location (location);
781                 }
782                 else {
783                         erow = manage (new LocationEditRow(session, location));
784                         erow->remove_requested.connect (mem_fun(*this, &LocationUI::location_remove_requested));
785                         range_children.push_back(Box_Helpers::Element(*erow,  PACK_SHRINK, 1, PACK_START));
786                 }
787         }
788
789         range_rows.show_all();
790         location_rows.show_all();
791 }
792
793 void
794 LocationUI::add_new_location()
795 {
796         if (session) {
797                 jack_nframes_t where = session->audible_frame();
798                 Location *location = new Location (where, where, "mark", Location::IsMark);
799                 session->begin_reversible_command (_("add marker"));
800                 session->add_undo (session->locations()->get_memento());
801                 session->locations()->add (location, true);
802                 session->add_redo_no_execute (session->locations()->get_memento());
803                 session->commit_reversible_command ();
804         }
805         
806 }
807
808 void
809 LocationUI::add_new_range()
810 {
811         if (session) {
812                 jack_nframes_t where = session->audible_frame();
813                 Location *location = new Location (where, where, "unnamed");
814                 session->begin_reversible_command (_("add range marker"));
815                 session->add_undo (session->locations()->get_memento());
816                 session->locations()->add (location, true);
817                 session->add_redo_no_execute (session->locations()->get_memento());
818                 session->commit_reversible_command ();
819         }
820 }
821
822
823 void
824 LocationUI::refresh_location_list_s (Change ignored)
825 {
826         ENSURE_GUI_THREAD(bind (mem_fun(*this, &LocationUI::refresh_location_list_s), ignored));
827         
828         refresh_location_list ();
829 }
830
831 void
832 LocationUI::refresh_location_list ()
833 {
834         ENSURE_GUI_THREAD(mem_fun(*this, &LocationUI::refresh_location_list));
835         using namespace Box_Helpers;
836
837         BoxList & loc_children = location_rows.children();
838         BoxList & range_children = range_rows.children();
839
840         loc_children.clear();
841         range_children.clear();
842
843         if (session) {
844                 session->locations()->apply (*this, &LocationUI::map_locations);
845         }
846         
847 }
848
849 void
850 LocationUI::set_session(ARDOUR::Session* sess)
851 {
852         ArdourDialog::set_session (sess);
853
854         if (session) {
855                 session->locations()->changed.connect (mem_fun(*this, &LocationUI::refresh_location_list));
856                 session->locations()->StateChanged.connect (mem_fun(*this, &LocationUI::refresh_location_list_s));
857                 session->locations()->added.connect (mem_fun(*this, &LocationUI::location_added));
858                 session->locations()->removed.connect (mem_fun(*this, &LocationUI::location_removed));
859                 session->going_away.connect (mem_fun(*this, &LocationUI::session_gone));
860         }
861         refresh_location_list ();
862 }
863
864 void
865 LocationUI::session_gone()
866 {
867         ENSURE_GUI_THREAD(mem_fun(*this, &LocationUI::session_gone));
868         
869         hide_all();
870
871         using namespace Box_Helpers;
872         BoxList & loc_children = location_rows.children();
873         BoxList & range_children = range_rows.children();
874
875         loc_children.clear();
876         range_children.clear();
877
878         loop_edit_row.set_session (0);
879         loop_edit_row.set_location (0);
880
881         punch_edit_row.set_session (0);
882         punch_edit_row.set_location (0);
883         
884         ArdourDialog::session_gone();
885 }
886