change tooltip for group tab to suggest click-to-(de)activate
[ardour.git] / gtk2_ardour / startup.cc
1 /*
2     Copyright (C) 2010 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 <fstream>
21 #include <algorithm>
22
23 #include <gtkmm/main.h>
24 #include <gtkmm/filechooser.h>
25
26 #include "pbd/failed_constructor.h"
27 #include "pbd/file_utils.h"
28 #include "pbd/filesystem.h"
29 #include "pbd/replace_all.h"
30 #include "pbd/whitespace.h"
31
32 #include "ardour/filesystem_paths.h"
33 #include "ardour/recent_sessions.h"
34 #include "ardour/session.h"
35 #include "ardour/session_state_utils.h"
36 #include "ardour/template_utils.h"
37
38 #include "startup.h"
39 #include "opts.h"
40 #include "engine_dialog.h"
41 #include "i18n.h"
42 #include "utils.h"
43
44 using namespace std;
45 using namespace Gtk;
46 using namespace Gdk;
47 using namespace Glib;
48 using namespace PBD;
49 using namespace ARDOUR;
50
51 ArdourStartup* ArdourStartup::the_startup = 0;
52
53 static string poor_mans_glob (string path)
54 {
55         string copy = path;
56         replace_all (copy, "~", Glib::get_home_dir());
57         return copy;
58 }
59
60
61 ArdourStartup::ArdourStartup ()
62         : _response (RESPONSE_OK)
63         , ic_new_session_button (_("Open a new session"))
64         , ic_existing_session_button (_("Open an existing session"))
65         , monitor_via_hardware_button (_("Use an external mixer or the hardware mixer of your audio interface.\n\
66 Ardour will play NO role in monitoring"))
67         , monitor_via_ardour_button (string_compose (_("Ask %1 to playback material as it is being recorded"), PROGRAM_NAME))
68         , new_folder_chooser (FILE_CHOOSER_ACTION_SELECT_FOLDER)
69         , more_new_session_options_button (_("I'd like more options for this session"))
70         , _output_limit_count_adj (1, 0, 100, 1, 10, 0)
71         , _input_limit_count_adj (1, 0, 100, 1, 10, 0)
72         , _master_bus_channel_count_adj (2, 0, 100, 1, 10, 0)
73         , _existing_session_chooser_used (false)
74 {
75         audio_page_index = -1;
76         initial_choice_index = -1;
77         new_user_page_index = -1;
78         default_folder_page_index = -1;
79         monitoring_page_index = -1;
80         session_page_index = -1;
81         final_page_index = -1;
82         session_options_page_index = -1;
83         new_only = false;
84
85         engine_dialog = 0;
86         config_modified = false;
87         default_dir_chooser = 0;
88
89         use_template_button.set_group (session_template_group);
90         use_session_as_template_button.set_group (session_template_group);
91
92         set_keep_above (true);
93         set_resizable (false);
94         set_position (WIN_POS_CENTER);
95         set_border_width (12);
96
97         if ((icon_pixbuf = ::get_icon ("ardour_icon_48px")) == 0) {
98                 throw failed_constructor();
99         }
100
101         sys::path been_here_before = user_config_directory();
102         been_here_before /= ".a3"; // XXXX use more specific version so we can catch upgrades
103         new_user = !exists (been_here_before);
104
105         bool need_audio_setup = !EngineControl::engine_running();
106
107         if (new_user) {
108                 /* "touch" the file */
109                 ofstream fout (been_here_before.to_string().c_str());
110                 setup_new_user_page ();
111                 setup_first_time_config_page ();
112                 setup_monitoring_choice_page ();
113                 setup_monitor_section_choice_page ();
114
115                 if (need_audio_setup) {
116                         setup_audio_page ();
117                 }
118
119         } else {
120
121                 if (need_audio_setup) {
122                         setup_audio_page ();
123                 }
124
125                 setup_initial_choice_page ();
126         }
127
128         setup_session_page ();
129         setup_more_options_page ();
130
131         if (new_user) {
132                 setup_final_page ();
133         }
134
135         the_startup = this;
136 }
137
138 ArdourStartup::~ArdourStartup ()
139 {
140 }
141
142 void
143 ArdourStartup::set_new_only (bool yn)
144 {
145         new_only = yn;
146
147         if (new_only) {
148                 ic_vbox.hide ();
149         } else {
150                 ic_vbox.show ();
151         }
152 }
153
154 void
155 ArdourStartup::set_load_template( string load_template )
156 {
157     use_template_button.set_active( false );
158     load_template_override = load_template;
159 }
160
161 bool
162 ArdourStartup::use_session_template ()
163 {
164         if (!load_template_override.empty())
165                 return true;
166
167         if (use_template_button.get_active()) {
168                 return template_chooser.get_active_row_number() > 0;
169         } else {
170                 return !session_template_chooser.get_filename().empty();
171         }
172 }
173
174 std::string
175 ArdourStartup::session_template_name ()
176 {
177         if (!load_template_override.empty()) {
178             string the_path = (ARDOUR::user_template_directory()/ (load_template_override + ".template")).to_string();
179                 return the_path;
180         }
181
182         if (ic_existing_session_button.get_active()) {
183                 return string();
184         }
185
186         if (use_template_button.get_active()) {
187                 TreeModel::iterator iter = template_chooser.get_active ();
188                 TreeModel::Row row = (*iter);
189                 string s = row[session_template_columns.path];
190                 return s;
191         } else {
192                 return session_template_chooser.get_filename();
193
194         }
195 }
196
197 std::string
198 ArdourStartup::session_name (bool& should_be_new)
199 {
200         if (ic_new_session_button.get_active()) {
201                 should_be_new = true;
202                 string val = new_name_entry.get_text ();
203                 strip_whitespace_edges (val);
204                 return val;
205         } else if (_existing_session_chooser_used) {
206                 /* existing session chosen from file chooser */
207                 should_be_new = false;
208                 return existing_session_chooser.get_filename ();
209         } else {
210                 /* existing session chosen from recent list */
211                 should_be_new = false;
212
213                 TreeIter iter = recent_session_display.get_selection()->get_selected();
214
215                 if (iter) {
216                         return (*iter)[recent_session_columns.visible_name];
217                 }
218
219                 return "";
220         }
221 }
222
223 std::string
224 ArdourStartup::session_folder ()
225 {
226         if (ic_new_session_button.get_active()) {
227                 std::string legal_session_folder_name = legalize_for_path (new_name_entry.get_text());
228                 return Glib::build_filename (new_folder_chooser.get_current_folder(), legal_session_folder_name);
229         } else if (_existing_session_chooser_used) {
230                 /* existing session chosen from file chooser */
231                 return existing_session_chooser.get_current_folder ();
232         } else {
233                 /* existing session chosen from recent list */
234                 TreeIter iter = recent_session_display.get_selection()->get_selected();
235
236                 if (iter) {
237                         return (*iter)[recent_session_columns.fullpath];
238                 }
239                 return "";
240         }
241 }
242
243 void
244 ArdourStartup::setup_audio_page ()
245 {
246         engine_dialog = manage (new EngineControl);
247
248         engine_dialog->set_border_width (12);
249
250         engine_dialog->show_all ();
251
252         audio_page_index = append_page (*engine_dialog);
253         set_page_type (*engine_dialog, ASSISTANT_PAGE_CONTENT);
254         set_page_title (*engine_dialog, _("Audio / MIDI Setup"));
255
256         /* the default parameters should work, so the page is potentially complete */
257
258         set_page_complete (*engine_dialog, true);
259 }
260
261 void
262 ArdourStartup::setup_new_user_page ()
263 {
264         Label* foomatic = manage (new Label);
265
266         foomatic->set_markup (string_compose (_("\
267 <span size=\"larger\">%1 is a digital audio workstation. You can use it to\n\
268 record, edit and mix multi-track audio. You can produce your\n\
269 own CDs, mix video soundtracks, or just experiment with new\n\
270 ideas about music and sound.\n\
271 \n\
272 There are a few things that need to configured before you start\n\
273 using the program.</span>\
274 "), PROGRAM_NAME));
275
276         HBox* hbox = manage (new HBox);
277         HBox* vbox = manage (new HBox);
278
279         vbox->set_border_width (24);
280
281         hbox->pack_start (*foomatic, true, true);
282         vbox->pack_start (*hbox, true, true);
283
284         foomatic->show ();
285         hbox->show ();
286         vbox->show ();
287
288         new_user_page_index = append_page (*vbox);
289         set_page_type (*vbox, ASSISTANT_PAGE_INTRO);
290         set_page_title (*vbox, string_compose (_("Welcome to %1"), PROGRAM_NAME));
291         set_page_header_image (*vbox, icon_pixbuf);
292         set_page_complete (*vbox, true);
293 }
294
295 void
296 ArdourStartup::default_dir_changed ()
297 {
298         Config->set_default_session_parent_dir (default_dir_chooser->get_current_folder());
299         config_changed ();
300 }
301
302 void
303 ArdourStartup::config_changed ()
304 {
305         config_modified = true;
306 }
307
308 void
309 ArdourStartup::setup_first_time_config_page ()
310 {
311         default_dir_chooser = manage (new FileChooserButton (string_compose (_("Default folder for %1 sessions"), PROGRAM_NAME),
312                                                              FILE_CHOOSER_ACTION_SELECT_FOLDER));
313         Gtk::Label* txt = manage (new Label);
314         HBox* hbox = manage (new HBox);
315         VBox* vbox = manage (new VBox);
316
317         txt->set_markup (string_compose (_("\
318 Each project that you work on with %1 has its own folder.\n\
319 These can require a lot of disk space if you are recording audio.\n\
320 \n\
321 Where would you like new %1 sessions to be stored by default?\n\n\
322 <i>(You can put new sessions anywhere, this is just a default)</i>"), PROGRAM_NAME));
323         txt->set_alignment (0.0, 0.0);
324
325         vbox->set_spacing (18);
326         vbox->set_border_width (24);
327
328         hbox->pack_start (*default_dir_chooser, false, true, 8);
329         vbox->pack_start (*txt, false, false);
330         vbox->pack_start (*hbox, false, true);
331
332         default_dir_chooser->set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir()));
333         default_dir_chooser->signal_current_folder_changed().connect (sigc::mem_fun (*this, &ArdourStartup::default_dir_changed));
334         default_dir_chooser->show ();
335
336         vbox->show_all ();
337
338         default_folder_page_index = append_page (*vbox);
339         set_page_title (*vbox, _("Default folder for new sessions"));
340         set_page_header_image (*vbox, icon_pixbuf);
341         set_page_type (*vbox, ASSISTANT_PAGE_CONTENT);
342
343         /* user can just skip all these settings if they want to */
344
345         set_page_complete (*vbox, true);
346 }
347
348 void
349 ArdourStartup::setup_monitoring_choice_page ()
350 {
351         mon_vbox.set_spacing (18);
352         mon_vbox.set_border_width (24);
353
354         HBox* hbox = manage (new HBox);
355         VBox* vbox = manage (new VBox);
356         RadioButton::Group g (monitor_via_hardware_button.get_group());
357         monitor_via_ardour_button.set_group (g);
358
359         monitor_label.set_markup("\
360 While recording instruments or vocals, you probably want to listen to the\n\
361 signal as well as record it. This is called \"monitoring\". There are\n\
362 different ways to do this depending on the equipment you have and the\n\
363 configuration of that equipment. The two most common are presented here.\n\
364 Please choose whichever one is right for your setup.\n\n\
365 <i>(You can change this preference at any time, via the Preferences dialog)</i>");
366         monitor_label.set_alignment (0.0, 0.0);
367
368         vbox->set_spacing (6);
369
370         vbox->pack_start (monitor_via_hardware_button, false, true);
371         vbox->pack_start (monitor_via_ardour_button, false, true);
372         hbox->pack_start (*vbox, true, true, 8);
373         mon_vbox.pack_start (monitor_label, false, false);
374         mon_vbox.pack_start (*hbox, false, false);
375
376         mon_vbox.show_all ();
377
378         monitoring_page_index = append_page (mon_vbox);
379         set_page_title (mon_vbox, _("Monitoring Choices"));
380         set_page_header_image (mon_vbox, icon_pixbuf);
381
382         /* user could just click on "Forward" if default
383          * choice is correct.
384          */
385
386         set_page_complete (mon_vbox, true);
387 }
388
389 void
390 ArdourStartup::setup_monitor_section_choice_page ()
391 {
392         mon_sec_vbox.set_spacing (18);
393         mon_sec_vbox.set_border_width (24);
394
395         HBox* hbox = manage (new HBox);
396         VBox* main_vbox = manage (new VBox);
397         VBox* vbox;
398         Label* l = manage (new Label);
399
400         main_vbox->set_spacing (32);
401
402         no_monitor_section_button.set_label (_("Use a Master bus directly"));
403         l->set_alignment (0.0, 1.0);
404         l->set_markup(_("Connect the Master bus directly to your hardware outputs.\n\
405 <i>Preferable for simple use</i>."));
406
407         vbox = manage (new VBox);
408         vbox->set_spacing (6);
409         vbox->pack_start (no_monitor_section_button, false, true);
410         vbox->pack_start (*l, false, true);
411
412         main_vbox->pack_start (*vbox, false, false);
413
414         use_monitor_section_button.set_label (_("Use an additional Monitor bus"));
415         l = manage (new Label);
416         l->set_alignment (0.0, 1.0);
417         l->set_text (_("Use a Monitor bus between Master bus and hardware outputs for \n\
418 greater control in monitoring without affecting the mix."));
419
420         vbox = manage (new VBox);
421         vbox->set_spacing (6);
422         vbox->pack_start (use_monitor_section_button, false, true);
423         vbox->pack_start (*l, false, true);
424
425         main_vbox->pack_start (*vbox, false, false);
426
427         RadioButton::Group g (use_monitor_section_button.get_group());
428         no_monitor_section_button.set_group (g);
429
430         if (Config->get_use_monitor_bus()) {
431                 use_monitor_section_button.set_active (true);
432         } else {
433                 no_monitor_section_button.set_active (true);
434         }
435
436         use_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &ArdourStartup::config_changed));
437         no_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &ArdourStartup::config_changed));
438         
439         monitor_section_label.set_markup(_("<i><small>(You can change this preference at any time, via the Preferences dialog)</small></i>"));
440         monitor_section_label.set_alignment (0.0, 0.0);
441
442         hbox->pack_start (*main_vbox, true, true, 8);
443         mon_sec_vbox.pack_start (*hbox, false, false);
444         mon_sec_vbox.pack_start (monitor_section_label, false, false);
445
446         mon_sec_vbox.show_all ();
447
448         monitor_section_page_index = append_page (mon_sec_vbox);
449         set_page_title (mon_sec_vbox, _("Monitor Section"));
450         set_page_header_image (mon_sec_vbox, icon_pixbuf);
451
452         /* user could just click on "Forward" if default
453          * choice is correct.
454          */
455
456         set_page_complete (mon_sec_vbox, true);
457 }
458
459 void
460 ArdourStartup::setup_initial_choice_page ()
461 {
462         ic_vbox.set_spacing (6);
463         ic_vbox.set_border_width (24);
464
465         RadioButton::Group g (ic_new_session_button.get_group());
466         ic_existing_session_button.set_group (g);
467
468         HBox* centering_hbox = manage (new HBox);
469         VBox* centering_vbox = manage (new VBox);
470
471         centering_vbox->set_spacing (6);
472
473         centering_vbox->pack_start (ic_new_session_button, false, true);
474         centering_vbox->pack_start (ic_existing_session_button, false, true);
475
476         ic_new_session_button.signal_button_press_event().connect(sigc::mem_fun(*this, &ArdourStartup::initial_button_press), false);
477         ic_new_session_button.signal_activate().connect(sigc::mem_fun(*this, &ArdourStartup::initial_button_activated), false);
478
479         ic_existing_session_button.signal_button_press_event().connect(sigc::mem_fun(*this, &ArdourStartup::initial_button_press), false);
480         ic_existing_session_button.signal_activate().connect(sigc::mem_fun(*this, &ArdourStartup::initial_button_activated), false);
481
482         centering_hbox->pack_start (*centering_vbox, true, true);
483
484         ic_vbox.pack_start (*centering_hbox, true, true);
485
486         ic_vbox.show_all ();
487
488         initial_choice_index = append_page (ic_vbox);
489         set_page_title (ic_vbox, _("What would you like to do ?"));
490         set_page_header_image (ic_vbox, icon_pixbuf);
491
492         /* user could just click on "Forward" if default
493          * choice is correct.
494          */
495
496         set_page_complete (ic_vbox, true);
497 }
498
499 bool
500 ArdourStartup::initial_button_press (GdkEventButton *event)
501 {
502         if (event && event->type == GDK_2BUTTON_PRESS && session_page_index != -1) {
503                 set_current_page(session_page_index);
504                 return true;
505         } else {
506                 return false;
507         }
508 }
509
510 void
511 ArdourStartup::initial_button_activated ()
512 {
513         set_current_page(session_page_index);
514 }
515
516 void
517 ArdourStartup::setup_session_page ()
518 {
519         session_vbox.set_border_width (24);
520
521         session_vbox.pack_start (session_hbox, true, true);
522         session_vbox.show_all ();
523
524         session_page_index = append_page (session_vbox);
525         /* initial setting */
526         set_page_type (session_vbox, ASSISTANT_PAGE_CONFIRM);
527 }
528
529 void
530 ArdourStartup::setup_final_page ()
531 {
532         final_page.set_text (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
533         final_page.show ();
534         final_page_index = append_page (final_page);
535         set_page_complete (final_page, true);
536         set_page_header_image (final_page, icon_pixbuf);
537         set_page_type (final_page, ASSISTANT_PAGE_CONFIRM);
538 }
539
540 void
541 ArdourStartup::on_cancel ()
542 {
543         _response = RESPONSE_CANCEL;
544         gtk_main_quit ();
545 }
546
547 bool
548 ArdourStartup::on_delete_event (GdkEventAny*)
549 {
550         _response = RESPONSE_CLOSE;
551         gtk_main_quit ();
552         return true;
553 }
554
555 void
556 ArdourStartup::on_apply ()
557 {
558         if (engine_dialog) {
559                 engine_dialog->setup_engine ();
560         }
561
562         if (config_modified) {
563
564                 if (default_dir_chooser) {
565                         Config->set_default_session_parent_dir (default_dir_chooser->get_current_folder());
566                 }
567
568                 if (monitor_via_hardware_button.get_active()) {
569                         Config->set_monitoring_model (ExternalMonitoring);
570                 } else if (monitor_via_ardour_button.get_active()) {
571                         Config->set_monitoring_model (SoftwareMonitoring);
572                 }
573
574                 Config->set_use_monitor_bus (use_monitor_section_button.get_active());
575
576                 Config->save_state ();
577         }
578
579         _response = RESPONSE_OK;
580         gtk_main_quit ();
581 }
582
583 void
584 ArdourStartup::on_prepare (Gtk::Widget* page)
585 {
586         if (page == &session_vbox) {
587
588                 if (ic_new_session_button.get_active()) {
589                         /* new session requested */
590                         setup_new_session_page ();
591                 } else {
592                         /* existing session requested */
593                         setup_existing_session_page ();
594                 }
595         }
596 }
597
598 void
599 ArdourStartup::populate_session_templates ()
600 {
601         vector<TemplateInfo> templates;
602
603         find_session_templates (templates);
604
605         template_model->clear ();
606
607         for (vector<TemplateInfo>::iterator x = templates.begin(); x != templates.end(); ++x) {
608                 TreeModel::Row row;
609
610                 row = *(template_model->append ());
611
612                 row[session_template_columns.name] = (*x).name;
613                 row[session_template_columns.path] = (*x).path;
614         }
615 }
616
617 static bool
618 lost_name_entry_focus (GdkEventFocus*)
619 {
620         cerr << "lost focus\n";
621         return false;
622 }
623                 
624 void
625 ArdourStartup::setup_new_session_page ()
626 {
627         if (!session_hbox.get_children().empty()) {
628                 session_hbox.remove (**session_hbox.get_children().begin());
629         }
630
631         session_new_vbox.set_spacing (18);
632
633         if (session_new_vbox.get_children().empty()) {
634                 VBox *vbox1 = manage (new VBox);
635                 HBox* hbox1 = manage (new HBox);
636                 Label* label1 = manage (new Label);
637
638                 vbox1->set_spacing (6);
639
640                 hbox1->set_spacing (6);
641                 hbox1->pack_start (*label1, false, false);
642                 hbox1->pack_start (new_name_entry, true, true);
643
644                 label1->set_text (_("Session name:"));
645
646
647                 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
648                         new_name_entry.set_text  (Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name));
649                         /* name provided - they can move right along */
650                         set_page_complete (session_vbox, true);
651                 }
652
653                 new_name_entry.signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::new_name_changed));
654                 new_name_entry.signal_activate().connect (sigc::mem_fun (*this, &ArdourStartup::move_along_now));
655
656                 vbox1->pack_start (*hbox1, true, true);
657
658                 /* --- */
659
660                 HBox* hbox2 = manage (new HBox);
661                 Label* label2 = manage (new Label);
662
663                 hbox2->set_spacing (6);
664                 hbox2->pack_start (*label2, false, false);
665                 hbox2->pack_start (new_folder_chooser, true, true);
666
667                 label2->set_text (_("Create session folder in:"));
668
669                 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
670                         new_folder_chooser.set_current_folder (poor_mans_glob (Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name)));
671                 } else {
672                         new_folder_chooser.set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir()));
673                 }
674                 new_folder_chooser.set_title (_("Select folder for session"));
675
676 #ifdef GTKOSX
677                 new_folder_chooser->add_shortcut_folder ("/Volumes");
678 #endif
679
680                 vbox1->pack_start (*hbox2, false, false);
681
682                 session_new_vbox.pack_start (*vbox1, false, false);
683
684                 /* --- */
685
686                 VBox *vbox2 = manage (new VBox);
687                 HBox* hbox3 = manage (new HBox);
688                 Label* label3 = manage (new Label);
689                 template_model = ListStore::create (session_template_columns);
690                 populate_session_templates ();
691
692                 vbox2->set_spacing (6);
693
694                 label3->set_markup (_("<b>Options</b>"));
695                 label3->set_alignment (0.0, 0.0);
696
697                 vbox2->pack_start (*label3, false, true);
698
699                 VBox *vbox3 = manage (new VBox);
700
701                 vbox3->set_spacing (6);
702
703                 if (!template_model->children().empty()) {
704
705                         HBox* hbox4a = manage (new HBox);
706                         use_template_button.set_label (_("Use this template"));
707
708                         TreeModel::Row row = *template_model->prepend ();
709                         row[session_template_columns.name] = (_("no template"));
710                         row[session_template_columns.path] = string();
711
712                         hbox4a->set_spacing (6);
713                         hbox4a->pack_start (use_template_button, false, false);
714                         hbox4a->pack_start (template_chooser, true, true);
715
716                         template_chooser.set_model (template_model);
717
718                         Gtk::CellRendererText* text_renderer = Gtk::manage (new Gtk::CellRendererText);
719                         text_renderer->property_editable() = false;
720
721                         template_chooser.pack_start (*text_renderer);
722                         template_chooser.add_attribute (text_renderer->property_text(), session_template_columns.name);
723                         template_chooser.set_active (0);
724
725                         use_template_button.show();
726                         template_chooser.show ();
727
728                         vbox3->pack_start (*hbox4a, false, false);
729                 }
730
731                 /* --- */
732
733                 if (!new_user) {
734                         session_template_chooser.set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir()));
735
736                         HBox* hbox4b = manage (new HBox);
737                         use_session_as_template_button.set_label (_("Use an existing session as a template:"));
738
739                         hbox4b->set_spacing (6);
740                         hbox4b->pack_start (use_session_as_template_button, false, false);
741                         hbox4b->pack_start (session_template_chooser, true, true);
742
743                         use_session_as_template_button.show ();
744                         session_template_chooser.show ();
745
746                         Gtk::FileFilter* template_filter = manage (new (Gtk::FileFilter));
747                         template_filter->add_pattern(X_("*.template"));
748                         session_template_chooser.set_filter (*template_filter);
749                         session_template_chooser.set_title (_("Select template"));
750
751                         vbox3->pack_start (*hbox4b, false, false);
752                 }
753
754                 /* --- */
755
756                 HBox* hbox5 = manage (new HBox);
757
758                 hbox5->set_spacing (6);
759                 hbox5->pack_start (more_new_session_options_button, false, false);
760
761                 more_new_session_options_button.show ();
762                 more_new_session_options_button.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::more_new_session_options_button_clicked));
763
764                 vbox3->pack_start (*hbox5, false, false);
765                 hbox3->pack_start (*vbox3, true, true, 8);
766                 vbox2->pack_start (*hbox3, false, false);
767
768                 /* --- */
769
770                 session_new_vbox.pack_start (*vbox2, false, false);
771         }
772
773         session_new_vbox.show_all ();
774         session_hbox.pack_start (session_new_vbox, true, true);
775         set_page_title (session_vbox, _("New Session"));
776         set_page_type (session_vbox, ASSISTANT_PAGE_CONFIRM);
777
778         new_name_entry.signal_map().connect (sigc::mem_fun (*this, &ArdourStartup::new_name_mapped));
779         new_name_entry.signal_focus_out_event().connect (sigc::ptr_fun (lost_name_entry_focus));
780 }
781
782 void
783 ArdourStartup::new_name_mapped ()
784 {
785         cerr << "Grab new name focus\n";
786         new_name_entry.grab_focus ();
787 }
788
789 void
790 ArdourStartup::new_name_changed ()
791 {
792         if (!new_name_entry.get_text().empty()) {
793                 set_page_complete (session_vbox, true);
794         } else {
795                 set_page_complete (session_vbox, false);
796         }
797 }
798
799 int
800 ArdourStartup::redisplay_recent_sessions ()
801 {
802         std::vector<sys::path> session_directories;
803         RecentSessionsSorter cmp;
804
805         recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
806         recent_session_model->clear ();
807
808         ARDOUR::RecentSessions rs;
809         ARDOUR::read_recent_sessions (rs);
810
811         if (rs.empty()) {
812                 recent_session_display.set_model (recent_session_model);
813                 return 0;
814         }
815         //
816         // sort them alphabetically
817         sort (rs.begin(), rs.end(), cmp);
818
819         for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
820                 session_directories.push_back ((*i).second);
821         }
822
823         for (vector<sys::path>::const_iterator i = session_directories.begin(); i != session_directories.end(); ++i)
824         {
825                 std::vector<sys::path> state_file_paths;
826
827                 // now get available states for this session
828
829                 get_state_files_in_directory (*i, state_file_paths);
830
831                 vector<string*>* states;
832                 vector<const gchar*> item;
833                 string fullpath = (*i).to_string();
834
835                 /* remove any trailing / */
836
837                 if (fullpath[fullpath.length()-1] == '/') {
838                         fullpath = fullpath.substr (0, fullpath.length()-1);
839                 }
840
841                 /* check whether session still exists */
842                 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
843                         /* session doesn't exist */
844                         continue;
845                 }
846
847                 /* now get available states for this session */
848
849                 if ((states = Session::possible_states (fullpath)) == 0) {
850                         /* no state file? */
851                         continue;
852                 }
853
854                 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
855
856                 Gtk::TreeModel::Row row = *(recent_session_model->append());
857
858                 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
859                 row[recent_session_columns.fullpath] = fullpath;
860
861                 if (state_file_names.size() > 1) {
862
863                         // add the children
864
865                         for (std::vector<std::string>::iterator i2 = state_file_names.begin();
866                                         i2 != state_file_names.end(); ++i2)
867                         {
868
869                                 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
870
871                                 child_row[recent_session_columns.visible_name] = *i2;
872                                 child_row[recent_session_columns.fullpath] = fullpath;
873                         }
874                 }
875         }
876
877         recent_session_display.set_model (recent_session_model);
878         return rs.size();
879 }
880
881 void
882 ArdourStartup::recent_session_row_selected ()
883 {
884         if (recent_session_display.get_selection()->count_selected_rows() > 0) {
885                 set_page_complete (session_vbox, true);
886         } else {
887                 set_page_complete (session_vbox, false);
888         }
889 }
890
891 void
892 ArdourStartup::setup_existing_session_page ()
893 {
894         recent_session_model = TreeStore::create (recent_session_columns);
895         redisplay_recent_sessions ();
896
897         if (!session_hbox.get_children().empty()) {
898                 session_hbox.remove (**session_hbox.get_children().begin());
899         }
900
901         if (session_existing_vbox.get_children().empty()) {
902
903                 recent_session_display.set_model (recent_session_model);
904                 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
905                 recent_session_display.set_headers_visible (false);
906                 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
907                 
908                 recent_session_display.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::recent_session_row_selected));
909                 
910                 recent_scroller.add (recent_session_display);
911                 recent_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
912                 recent_scroller.set_shadow_type (Gtk::SHADOW_IN);
913                 
914                 recent_session_display.show();
915                 
916                 recent_scroller.show();
917                 int cnt = redisplay_recent_sessions ();
918                 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ArdourStartup::recent_row_activated));
919                 
920                 if (cnt > 4) {
921                         recent_scroller.set_size_request (-1, 300);
922                 }
923
924                 session_existing_vbox.set_spacing (8);
925                 session_existing_vbox.pack_start (recent_scroller, true, true);
926
927                 existing_session_chooser.set_title (_("Select session file"));
928                 existing_session_chooser.signal_file_set().connect (sigc::mem_fun (*this, &ArdourStartup::existing_session_selected));
929                 
930 #ifdef GTKOSX
931                 existing_session_chooser->add_shortcut_folder ("/Volumes");
932 #endif
933                 
934                 HBox* hbox = manage (new HBox);
935                 hbox->set_spacing (4);
936                 hbox->pack_start (*manage (new Label (_("Browse:"))), PACK_SHRINK);
937                 hbox->pack_start (existing_session_chooser);
938                 session_existing_vbox.pack_start (*hbox);
939                 hbox->show_all ();
940         }
941         
942         session_existing_vbox.show_all ();
943         session_hbox.pack_start (session_existing_vbox, true, true);
944
945         set_page_title (session_vbox, _("Select a session"));
946         set_page_type (session_vbox, ASSISTANT_PAGE_CONFIRM);
947 }
948
949 void
950 ArdourStartup::more_new_session_options_button_clicked ()
951 {
952         if (more_new_session_options_button.get_active()) {
953                 more_options_vbox.show_all ();
954                 set_page_type (more_options_vbox, ASSISTANT_PAGE_CONFIRM);
955                 set_page_type (session_vbox, ASSISTANT_PAGE_CONTENT);
956         } else {
957                 set_page_type (session_vbox, ASSISTANT_PAGE_CONFIRM);
958                 more_options_vbox.hide ();
959         }
960 }
961
962 void
963 ArdourStartup::setup_more_options_page ()
964 {
965         more_options_vbox.set_border_width (24);
966
967         _output_limit_count.set_adjustment (_output_limit_count_adj);
968         _input_limit_count.set_adjustment (_input_limit_count_adj);
969         _master_bus_channel_count.set_adjustment (_master_bus_channel_count_adj);
970
971         chan_count_label_1.set_text (_("channels"));
972         chan_count_label_3.set_text (_("channels"));
973         chan_count_label_4.set_text (_("channels"));
974
975         chan_count_label_1.set_alignment(0,0.5);
976         chan_count_label_1.set_padding(0,0);
977         chan_count_label_1.set_line_wrap(false);
978
979         chan_count_label_3.set_alignment(0,0.5);
980         chan_count_label_3.set_padding(0,0);
981         chan_count_label_3.set_line_wrap(false);
982
983         chan_count_label_4.set_alignment(0,0.5);
984         chan_count_label_4.set_padding(0,0);
985         chan_count_label_4.set_line_wrap(false);
986
987         bus_label.set_markup (_("<b>Busses</b>"));
988         input_label.set_markup (_("<b>Inputs</b>"));
989         output_label.set_markup (_("<b>Outputs</b>"));
990
991         _master_bus_channel_count.set_flags(Gtk::CAN_FOCUS);
992         _master_bus_channel_count.set_update_policy(Gtk::UPDATE_ALWAYS);
993         _master_bus_channel_count.set_numeric(true);
994         _master_bus_channel_count.set_digits(0);
995         _master_bus_channel_count.set_wrap(false);
996
997         _create_master_bus.set_label (_("Create master bus"));
998         _create_master_bus.set_flags(Gtk::CAN_FOCUS);
999         _create_master_bus.set_relief(Gtk::RELIEF_NORMAL);
1000         _create_master_bus.set_mode(true);
1001         _create_master_bus.set_active(true);
1002         _create_master_bus.set_border_width(0);
1003
1004         advanced_table.set_row_spacings(0);
1005         advanced_table.set_col_spacings(0);
1006
1007         _connect_inputs.set_label (_("Automatically connect to physical_inputs"));
1008         _connect_inputs.set_flags(Gtk::CAN_FOCUS);
1009         _connect_inputs.set_relief(Gtk::RELIEF_NORMAL);
1010         _connect_inputs.set_mode(true);
1011         _connect_inputs.set_active(true);
1012         _connect_inputs.set_border_width(0);
1013
1014         _limit_input_ports.set_label (_("Use only"));
1015         _limit_input_ports.set_flags(Gtk::CAN_FOCUS);
1016         _limit_input_ports.set_relief(Gtk::RELIEF_NORMAL);
1017         _limit_input_ports.set_mode(true);
1018         _limit_input_ports.set_sensitive(true);
1019         _limit_input_ports.set_border_width(0);
1020
1021         _input_limit_count.set_flags(Gtk::CAN_FOCUS);
1022         _input_limit_count.set_update_policy(Gtk::UPDATE_ALWAYS);
1023         _input_limit_count.set_numeric(true);
1024         _input_limit_count.set_digits(0);
1025         _input_limit_count.set_wrap(false);
1026         _input_limit_count.set_sensitive(false);
1027
1028         bus_hbox.pack_start (bus_table, Gtk::PACK_SHRINK, 18);
1029
1030         bus_label.set_alignment(0, 0.5);
1031         bus_label.set_padding(0,0);
1032         bus_label.set_line_wrap(false);
1033         bus_label.set_selectable(false);
1034         bus_label.set_use_markup(true);
1035         bus_frame.set_shadow_type(Gtk::SHADOW_NONE);
1036         bus_frame.set_label_align(0,0.5);
1037         bus_frame.add(bus_hbox);
1038         bus_frame.set_label_widget(bus_label);
1039
1040         bus_table.set_row_spacings (0);
1041         bus_table.set_col_spacings (0);
1042         bus_table.attach (_create_master_bus, 0, 1, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
1043         bus_table.attach (_master_bus_channel_count, 1, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
1044         bus_table.attach (chan_count_label_1, 2, 3, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 6, 0);
1045
1046         input_port_limit_hbox.pack_start(_limit_input_ports, Gtk::PACK_SHRINK, 6);
1047         input_port_limit_hbox.pack_start(_input_limit_count, Gtk::PACK_SHRINK, 0);
1048         input_port_limit_hbox.pack_start(chan_count_label_3, Gtk::PACK_SHRINK, 6);
1049         input_port_vbox.pack_start(_connect_inputs, Gtk::PACK_SHRINK, 0);
1050         input_port_vbox.pack_start(input_port_limit_hbox, Gtk::PACK_EXPAND_PADDING, 0);
1051         input_table.set_row_spacings(0);
1052         input_table.set_col_spacings(0);
1053         input_table.attach(input_port_vbox, 0, 1, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 6, 6);
1054
1055         input_hbox.pack_start (input_table, Gtk::PACK_SHRINK, 18);
1056
1057         input_label.set_alignment(0, 0.5);
1058         input_label.set_padding(0,0);
1059         input_label.set_line_wrap(false);
1060         input_label.set_selectable(false);
1061         input_label.set_use_markup(true);
1062         input_frame.set_shadow_type(Gtk::SHADOW_NONE);
1063         input_frame.set_label_align(0,0.5);
1064         input_frame.add(input_hbox);
1065         input_frame.set_label_widget(input_label);
1066
1067         _connect_outputs.set_label (_("Automatically connect outputs"));
1068         _connect_outputs.set_flags(Gtk::CAN_FOCUS);
1069         _connect_outputs.set_relief(Gtk::RELIEF_NORMAL);
1070         _connect_outputs.set_mode(true);
1071         _connect_outputs.set_active(true);
1072         _connect_outputs.set_border_width(0);
1073         _limit_output_ports.set_label (_("Use only"));
1074         _limit_output_ports.set_flags(Gtk::CAN_FOCUS);
1075         _limit_output_ports.set_relief(Gtk::RELIEF_NORMAL);
1076         _limit_output_ports.set_mode(true);
1077         _limit_output_ports.set_sensitive(true);
1078         _limit_output_ports.set_border_width(0);
1079         _output_limit_count.set_flags(Gtk::CAN_FOCUS);
1080         _output_limit_count.set_update_policy(Gtk::UPDATE_ALWAYS);
1081         _output_limit_count.set_numeric(false);
1082         _output_limit_count.set_digits(0);
1083         _output_limit_count.set_wrap(false);
1084         _output_limit_count.set_sensitive(false);
1085         output_port_limit_hbox.pack_start(_limit_output_ports, Gtk::PACK_SHRINK, 6);
1086         output_port_limit_hbox.pack_start(_output_limit_count, Gtk::PACK_SHRINK, 0);
1087         output_port_limit_hbox.pack_start(chan_count_label_4, Gtk::PACK_SHRINK, 6);
1088
1089         _connect_outputs_to_master.set_label (_("... to master bus"));
1090         _connect_outputs_to_master.set_flags(Gtk::CAN_FOCUS);
1091         _connect_outputs_to_master.set_relief(Gtk::RELIEF_NORMAL);
1092         _connect_outputs_to_master.set_mode(true);
1093         _connect_outputs_to_master.set_active(false);
1094         _connect_outputs_to_master.set_border_width(0);
1095
1096         _connect_outputs_to_master.set_group (connect_outputs_group);
1097         _connect_outputs_to_physical.set_group (connect_outputs_group);
1098
1099         _connect_outputs_to_physical.set_label (_("... to physical outputs"));
1100         _connect_outputs_to_physical.set_flags(Gtk::CAN_FOCUS);
1101         _connect_outputs_to_physical.set_relief(Gtk::RELIEF_NORMAL);
1102         _connect_outputs_to_physical.set_mode(true);
1103         _connect_outputs_to_physical.set_active(false);
1104         _connect_outputs_to_physical.set_border_width(0);
1105
1106         output_conn_vbox.pack_start(_connect_outputs, Gtk::PACK_SHRINK, 0);
1107         output_conn_vbox.pack_start(_connect_outputs_to_master, Gtk::PACK_SHRINK, 0);
1108         output_conn_vbox.pack_start(_connect_outputs_to_physical, Gtk::PACK_SHRINK, 0);
1109         output_vbox.set_border_width(6);
1110
1111         output_port_vbox.pack_start(output_port_limit_hbox, Gtk::PACK_SHRINK, 0);
1112
1113         output_vbox.pack_start(output_conn_vbox);
1114         output_vbox.pack_start(output_port_vbox);
1115
1116         output_label.set_alignment(0, 0.5);
1117         output_label.set_padding(0,0);
1118         output_label.set_line_wrap(false);
1119         output_label.set_selectable(false);
1120         output_label.set_use_markup(true);
1121         output_frame.set_shadow_type(Gtk::SHADOW_NONE);
1122         output_frame.set_label_align(0,0.5);
1123
1124         output_hbox.pack_start (output_vbox, Gtk::PACK_SHRINK, 18);
1125
1126         output_frame.add(output_hbox);
1127         output_frame.set_label_widget(output_label);
1128
1129         more_options_vbox.pack_start(advanced_table, Gtk::PACK_SHRINK, 0);
1130         more_options_vbox.pack_start(bus_frame, Gtk::PACK_SHRINK, 6);
1131         more_options_vbox.pack_start(input_frame, Gtk::PACK_SHRINK, 6);
1132         more_options_vbox.pack_start(output_frame, Gtk::PACK_SHRINK, 0);
1133
1134         /* signals */
1135
1136         _connect_inputs.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::connect_inputs_clicked));
1137         _connect_outputs.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::connect_outputs_clicked));
1138         _limit_input_ports.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::limit_inputs_clicked));
1139         _limit_output_ports.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::limit_outputs_clicked));
1140         _create_master_bus.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::master_bus_button_clicked));
1141
1142         /* note that more_options_vbox is NOT visible by
1143          * default. this is entirely by design - this page
1144          * should be skipped unless explicitly requested.
1145          */
1146
1147         session_options_page_index = append_page (more_options_vbox);
1148         set_page_title (more_options_vbox, _("Advanced Session Options"));
1149         set_page_complete (more_options_vbox, true);
1150 }
1151
1152 bool
1153 ArdourStartup::create_master_bus() const
1154 {
1155         return _create_master_bus.get_active();
1156 }
1157
1158 int
1159 ArdourStartup::master_channel_count() const
1160 {
1161         return _master_bus_channel_count.get_value_as_int();
1162 }
1163
1164 bool
1165 ArdourStartup::connect_inputs() const
1166 {
1167         return _connect_inputs.get_active();
1168 }
1169
1170 bool
1171 ArdourStartup::limit_inputs_used_for_connection() const
1172 {
1173         return _limit_input_ports.get_active();
1174 }
1175
1176 int
1177 ArdourStartup::input_limit_count() const
1178 {
1179         return _input_limit_count.get_value_as_int();
1180 }
1181
1182 bool
1183 ArdourStartup::connect_outputs() const
1184 {
1185         return _connect_outputs.get_active();
1186 }
1187
1188 bool
1189 ArdourStartup::limit_outputs_used_for_connection() const
1190 {
1191         return _limit_output_ports.get_active();
1192 }
1193
1194 int
1195 ArdourStartup::output_limit_count() const
1196 {
1197         return _output_limit_count.get_value_as_int();
1198 }
1199
1200 bool
1201 ArdourStartup::connect_outs_to_master() const
1202 {
1203         return _connect_outputs_to_master.get_active();
1204 }
1205
1206 bool
1207 ArdourStartup::connect_outs_to_physical() const
1208 {
1209         return _connect_outputs_to_physical.get_active();
1210 }
1211
1212 void
1213 ArdourStartup::connect_inputs_clicked ()
1214 {
1215         _limit_input_ports.set_sensitive(_connect_inputs.get_active());
1216
1217         if (_connect_inputs.get_active() && _limit_input_ports.get_active()) {
1218                 _input_limit_count.set_sensitive(true);
1219         } else {
1220                 _input_limit_count.set_sensitive(false);
1221         }
1222 }
1223
1224 void
1225 ArdourStartup::connect_outputs_clicked ()
1226 {
1227         _limit_output_ports.set_sensitive(_connect_outputs.get_active());
1228
1229         if (_connect_outputs.get_active() && _limit_output_ports.get_active()) {
1230                 _output_limit_count.set_sensitive(true);
1231         } else {
1232                 _output_limit_count.set_sensitive(false);
1233         }
1234 }
1235
1236 void
1237 ArdourStartup::limit_inputs_clicked ()
1238 {
1239         _input_limit_count.set_sensitive(_limit_input_ports.get_active());
1240 }
1241
1242 void
1243 ArdourStartup::limit_outputs_clicked ()
1244 {
1245         _output_limit_count.set_sensitive(_limit_output_ports.get_active());
1246 }
1247
1248 void
1249 ArdourStartup::master_bus_button_clicked ()
1250 {
1251         bool yn = _create_master_bus.get_active();
1252
1253         _master_bus_channel_count.set_sensitive(yn);
1254 }
1255
1256 void
1257 ArdourStartup::move_along_now ()
1258 {
1259         gint cur = get_current_page ();
1260
1261         if (cur == session_page_index) {
1262                 if (more_new_session_options_button.get_active()) {
1263                         set_current_page (session_options_page_index);
1264                 } else {
1265                         on_apply ();
1266                 }
1267         }
1268 }
1269
1270 void
1271 ArdourStartup::recent_row_activated (const Gtk::TreePath&, Gtk::TreeViewColumn*)
1272 {
1273         set_page_complete (session_vbox, true);
1274         move_along_now ();
1275 }
1276
1277 void
1278 ArdourStartup::existing_session_selected ()
1279 {
1280         _existing_session_chooser_used = true;
1281
1282         set_page_complete (session_vbox, true);
1283         move_along_now ();
1284 }