/* Copyright (C) 2010 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef WAF_BUILD #include "gtk2ardour-config.h" #endif #include #include #include #include #include "pbd/failed_constructor.h" #include "pbd/file_utils.h" #include "pbd/replace_all.h" #include "pbd/whitespace.h" #include "pbd/stacktrace.h" #include "pbd/openuri.h" #include "ardour/audioengine.h" #include "ardour/filesystem_paths.h" #include "ardour/recent_sessions.h" #include "ardour/session.h" #include "ardour/session_state_utils.h" #include "ardour/template_utils.h" #include "ardour/filename_extensions.h" #include "ardour_ui.h" #include "startup.h" #include "opts.h" #include "engine_dialog.h" #include "i18n.h" #include "utils.h" using namespace std; using namespace Gtk; using namespace Gdk; using namespace Glib; using namespace PBD; using namespace ARDOUR; ArdourStartup* ArdourStartup::the_startup = 0; static string poor_mans_glob (string path) { string copy = path; replace_all (copy, "~", Glib::get_home_dir()); return copy; } ArdourStartup::ArdourStartup (bool require_new, const std::string& session_name, const std::string& session_path, const std::string& template_name) : _response (RESPONSE_OK) , config_modified (false) , new_only (require_new) , default_dir_chooser (0) , monitor_via_hardware_button (string_compose (_("Use an external mixer or the hardware mixer of your audio interface.\n" "%1 will play NO role in monitoring"), PROGRAM_NAME)) , monitor_via_ardour_button (string_compose (_("Ask %1 to play back material as it is being recorded"), PROGRAM_NAME)) , new_folder_chooser (FILE_CHOOSER_ACTION_SELECT_FOLDER) , more_new_session_options_button (_("Advanced options ...")) , _output_limit_count_adj (1, 0, 100, 1, 10, 0) , _input_limit_count_adj (1, 0, 100, 1, 10, 0) , _master_bus_channel_count_adj (2, 0, 100, 1, 10, 0) , audio_page_index (-1) , new_user_page_index (-1) , default_folder_page_index (-1) , monitoring_page_index (-1) , new_session_page_index (-1) , initial_choice_index (-1) , final_page_index (-1) , session_options_page_index (-1) , _existing_session_chooser_used (false) { new_user = !Glib::file_test (been_here_before_path(), Glib::FILE_TEST_EXISTS); need_session_info = (session_name.empty() || require_new); _provided_session_name = session_name; _provided_session_path = session_path; if (need_session_info || new_user) { use_template_button.set_group (session_template_group); use_session_as_template_button.set_group (session_template_group); set_keep_above (true); set_position (WIN_POS_CENTER); set_border_width (12); if ((icon_pixbuf = ::get_icon ("ardour_icon_48px")) == 0) { throw failed_constructor(); } list > window_icons; Glib::RefPtr icon; if ((icon = ::get_icon ("ardour_icon_16px")) != 0) { window_icons.push_back (icon); } if ((icon = ::get_icon ("ardour_icon_22px")) != 0) { window_icons.push_back (icon); } if ((icon = ::get_icon ("ardour_icon_32px")) != 0) { window_icons.push_back (icon); } if ((icon = ::get_icon ("ardour_icon_48px")) != 0) { window_icons.push_back (icon); } if (!window_icons.empty ()) { set_default_icon_list (window_icons); } #ifdef __APPLE__ setup_prerelease_page (); #endif if (new_user) { setup_new_user_page (); setup_first_time_config_page (); setup_monitoring_choice_page (); setup_monitor_section_choice_page (); setup_final_page (); setup_new_session_page (); } else { if (!new_only) { setup_initial_choice_page (); } setup_new_session_page (); } if (!template_name.empty()) { use_template_button.set_active (false); load_template_override = template_name; } } the_startup = this; } ArdourStartup::~ArdourStartup () { } bool ArdourStartup::ready_without_display () const { return !new_user && !need_session_info; } void ArdourStartup::setup_prerelease_page () { VBox* vbox = manage (new VBox); Label* label = manage (new Label); label->set_markup (string_compose (_("Welcome to this BETA release of Ardour %1\n\n\ Ardour %1 has been released for Linux but because of the lack of testers,\n\ it is still at the beta stage on OS X. So, a few guidelines:\n\ \n\ 1) Please do NOT use this software with the expectation that it is stable or reliable\n\ though it may be so, depending on your workflow.\n\ 2) Please do NOT use the forums at ardour.org to report issues.\n\ 3) Please DO use the bugtracker at http://tracker.ardour.org/ to report issues\n\ making sure to note the product version number as %1-beta.\n\ 4) Please DO use the ardour-users mailing list to discuss ideas and pass on comments.\n\ 5) Please DO join us on IRC for real time discussions about ardour3. You\n\ can get there directly from Ardour via the Help->Chat menu option.\n\ \n\ Full information on all the above can be found on the support page at\n\ \n\ http://ardour.org/support\n\ "), VERSIONSTRING)); vbox->set_border_width (12); vbox->pack_start (*label, false, false, 12); vbox->show_all (); append_page (*vbox); set_page_type (*vbox, ASSISTANT_PAGE_CONTENT); set_page_title (*vbox, _("This is a BETA RELEASE")); set_page_complete (*vbox, true); } bool ArdourStartup::use_session_template () { if (!load_template_override.empty()) { return true; } if (use_template_button.get_active()) { return template_chooser.get_active_row_number() > 0; } else { return !session_template_chooser.get_filename().empty(); } } std::string ArdourStartup::session_template_name () { if (!load_template_override.empty()) { string the_path (ARDOUR::user_template_directory()); return Glib::build_filename (the_path, load_template_override + ARDOUR::template_suffix); } if (use_template_button.get_active()) { TreeModel::iterator iter = template_chooser.get_active (); TreeModel::Row row = (*iter); string s = row[session_template_columns.path]; return s; } else { return session_template_chooser.get_filename(); } } std::string ArdourStartup::session_name (bool& should_be_new) { if (ready_without_display()) { return _provided_session_name; } /* Try recent session selection */ TreeIter iter = recent_session_display.get_selection()->get_selected(); if (iter) { should_be_new = false; return (*iter)[recent_session_columns.visible_name]; } if (_existing_session_chooser_used) { /* existing session chosen from file chooser */ should_be_new = false; return existing_session_chooser.get_filename (); } else { should_be_new = true; string val = new_name_entry.get_text (); strip_whitespace_edges (val); return val; } } std::string ArdourStartup::session_folder () { if (ready_without_display()) { return _provided_session_path; } /* Try recent session selection */ TreeIter iter = recent_session_display.get_selection()->get_selected(); if (iter) { return (*iter)[recent_session_columns.fullpath]; } if (_existing_session_chooser_used) { /* existing session chosen from file chooser */ return existing_session_chooser.get_current_folder (); } else { std::string legal_session_folder_name = legalize_for_path (new_name_entry.get_text()); return Glib::build_filename (new_folder_chooser.get_current_folder(), legal_session_folder_name); } } void ArdourStartup::setup_new_user_page () { Label* foomatic = manage (new Label); foomatic->set_markup (string_compose (_("\ %1 is a digital audio workstation. You can use it to \ record, edit and mix multi-track audio. You can produce your \ own CDs, mix video soundtracks, or experiment with new \ ideas about music and sound. \ \n\n\ There are a few things that need to be configured before you start \ using the program. \ "), PROGRAM_NAME)); foomatic->set_justify (JUSTIFY_FILL); foomatic->set_line_wrap (); HBox* hbox = manage (new HBox); HBox* vbox = manage (new HBox); vbox->set_border_width (24); hbox->pack_start (*foomatic, true, true); vbox->pack_start (*hbox, true, true); foomatic->show (); hbox->show (); vbox->show (); new_user_page_index = append_page (*vbox); set_page_type (*vbox, ASSISTANT_PAGE_INTRO); set_page_title (*vbox, string_compose (_("Welcome to %1"), PROGRAM_NAME)); set_page_header_image (*vbox, icon_pixbuf); set_page_complete (*vbox, true); } void ArdourStartup::default_dir_changed () { Config->set_default_session_parent_dir (default_dir_chooser->get_filename()); // make new session folder chooser point to the new default new_folder_chooser.set_current_folder (Config->get_default_session_parent_dir()); config_changed (); } void ArdourStartup::config_changed () { config_modified = true; } void ArdourStartup::setup_first_time_config_page () { default_dir_chooser = manage (new FileChooserButton (string_compose (_("Default folder for %1 sessions"), PROGRAM_NAME), FILE_CHOOSER_ACTION_SELECT_FOLDER)); Gtk::Label* txt = manage (new Label); HBox* hbox = manage (new HBox); VBox* vbox = manage (new VBox); txt->set_markup (string_compose (_("\ Each project that you work on with %1 has its own folder.\n\ These can require a lot of disk space if you are recording audio.\n\ \n\ Where would you like new %1 sessions to be stored by default?\n\n\ (You can put new sessions anywhere, this is just a default)"), PROGRAM_NAME)); txt->set_alignment (0.0, 0.0); vbox->set_spacing (18); vbox->set_border_width (24); hbox->pack_start (*default_dir_chooser, false, true, 8); vbox->pack_start (*txt, false, false); vbox->pack_start (*hbox, false, true); default_dir_chooser->set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir())); default_dir_chooser->signal_current_folder_changed().connect (sigc::mem_fun (*this, &ArdourStartup::default_dir_changed)); default_dir_chooser->show (); vbox->show_all (); default_folder_page_index = append_page (*vbox); set_page_title (*vbox, _("Default folder for new sessions")); set_page_header_image (*vbox, icon_pixbuf); set_page_type (*vbox, ASSISTANT_PAGE_CONTENT); /* user can just skip all these settings if they want to */ set_page_complete (*vbox, true); } void ArdourStartup::setup_monitoring_choice_page () { mon_vbox.set_spacing (18); mon_vbox.set_border_width (24); HBox* hbox = manage (new HBox); VBox* vbox = manage (new VBox); /* first button will be on by default */ RadioButton::Group g (monitor_via_ardour_button.get_group()); monitor_via_hardware_button.set_group (g); monitor_label.set_markup(_("\ While recording instruments or vocals, you probably want to listen to the\n\ signal as well as record it. This is called \"monitoring\". There are\n\ different ways to do this depending on the equipment you have and the\n\ configuration of that equipment. The two most common are presented here.\n\ Please choose whichever one is right for your setup.\n\n\ (You can change this preference at any time, via the Preferences dialog)\n\n\ If you do not understand what this is about, just accept the default.")); monitor_label.set_alignment (0.0, 0.0); vbox->set_spacing (6); vbox->pack_start (monitor_via_hardware_button, false, true); vbox->pack_start (monitor_via_ardour_button, false, true); hbox->pack_start (*vbox, true, true, 8); mon_vbox.pack_start (monitor_label, false, false); mon_vbox.pack_start (*hbox, false, false); mon_vbox.show_all (); monitoring_page_index = append_page (mon_vbox); set_page_title (mon_vbox, _("Monitoring Choices")); set_page_header_image (mon_vbox, icon_pixbuf); /* user could just click on "Forward" if default * choice is correct. */ set_page_complete (mon_vbox, true); } void ArdourStartup::setup_monitor_section_choice_page () { mon_sec_vbox.set_spacing (18); mon_sec_vbox.set_border_width (24); HBox* hbox = manage (new HBox); VBox* main_vbox = manage (new VBox); VBox* vbox; Label* l = manage (new Label); main_vbox->set_spacing (32); no_monitor_section_button.set_label (_("Use a Master bus directly")); l->set_alignment (0.0, 1.0); l->set_markup(_("Connect the Master bus directly to your hardware outputs. This is preferable for simple usage.")); vbox = manage (new VBox); vbox->set_spacing (6); vbox->pack_start (no_monitor_section_button, false, true); vbox->pack_start (*l, false, true); main_vbox->pack_start (*vbox, false, false); use_monitor_section_button.set_label (_("Use an additional Monitor bus")); l = manage (new Label); l->set_alignment (0.0, 1.0); l->set_text (_("Use a Monitor bus between Master bus and hardware outputs for \n\ greater control in monitoring without affecting the mix.")); vbox = manage (new VBox); vbox->set_spacing (6); vbox->pack_start (use_monitor_section_button, false, true); vbox->pack_start (*l, false, true); main_vbox->pack_start (*vbox, false, false); RadioButton::Group g (use_monitor_section_button.get_group()); no_monitor_section_button.set_group (g); if (Config->get_use_monitor_bus()) { use_monitor_section_button.set_active (true); } else { no_monitor_section_button.set_active (true); } use_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &ArdourStartup::config_changed)); no_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &ArdourStartup::config_changed)); monitor_section_label.set_markup(_("You can change this preference at any time via the Preferences dialog.\nYou can also add or remove the monitor section to/from any session.\n\n\ If you do not understand what this is about, just accept the default.")); monitor_section_label.set_alignment (0.0, 0.0); hbox->pack_start (*main_vbox, true, true, 8); mon_sec_vbox.pack_start (*hbox, false, false); mon_sec_vbox.pack_start (monitor_section_label, false, false); mon_sec_vbox.show_all (); monitor_section_page_index = append_page (mon_sec_vbox); set_page_title (mon_sec_vbox, _("Monitor Section")); set_page_header_image (mon_sec_vbox, icon_pixbuf); /* user could just click on "Forward" if default * choice is correct. */ set_page_complete (mon_sec_vbox, true); } void ArdourStartup::setup_initial_choice_page () { ic_vbox.set_spacing (6); ic_vbox.set_border_width (24); /* append the page early because the recent session display will cause calls to set_page_complete() on this page. */ initial_choice_index = append_page (ic_vbox); set_page_title (ic_vbox, string_compose("%1 %2", PROGRAM_NAME, VERSIONSTRING)); set_page_header_image (ic_vbox, icon_pixbuf); HBox* centering_hbox = manage (new HBox); VBox* centering_vbox = manage (new VBox); centering_vbox->set_spacing (6); Label* new_label = manage (new Label); new_label->set_markup (string_compose ("%1", _("Create a new session"))); new_label->set_alignment (0, 0.5); ic_new_session_button.set_label (_("Configure the new session ...")); ic_new_session_button.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::new_session_button_clicked)); centering_vbox->pack_start (*new_label, false, false, 12); centering_vbox->pack_start (ic_new_session_button, false, true); /* Possible update message */ if (ARDOUR_UI::instance()->announce_string() != "" ) { Gtk::Frame *info_frame = manage(new Gtk::Frame); info_frame->set_shadow_type(SHADOW_ETCHED_OUT); centering_vbox->pack_start (*info_frame, false, false, 20); Box *info_box = manage (new VBox); info_box->set_border_width (12); info_box->set_spacing (6); info_box->set_name("mixbus_info_box"); info_box->pack_start (info_scroller_label, false, false); info_frame->add (*info_box); info_frame->show_all(); info_scroller_count = 0; info_scroller_connection = Glib::signal_timeout().connect (mem_fun(*this, &ArdourStartup::info_scroller_update), 50); Gtk::Button *updates_button = manage (new Gtk::Button (_("Check the website for more..."))); updates_button->signal_clicked().connect (mem_fun(*this, &ArdourStartup::updates_button_clicked) ); ARDOUR_UI::instance()->tooltips().set_tip (*updates_button, _("Click to open the program website in your web browser")); info_box->pack_start (*updates_button, false, false); } /* recent session scroller */ recent_label.set_no_show_all (true); recent_scroller.set_no_show_all (true); recent_label.set_markup (string_compose ("%1", _("Load a recent session"))); recent_label.set_alignment (0, 0.5); recent_session_model = TreeStore::create (recent_session_columns); recent_session_display.set_model (recent_session_model); recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name); recent_session_display.set_headers_visible (false); recent_session_display.get_selection()->set_mode (SELECTION_SINGLE); recent_session_display.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::recent_session_row_selected)); recent_scroller.add (recent_session_display); recent_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); recent_scroller.set_shadow_type (Gtk::SHADOW_IN); recent_session_display.show(); recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ArdourStartup::recent_row_activated)); centering_vbox->pack_start (recent_label, false, false, 12); centering_vbox->pack_start (recent_scroller, false, true); /* Browse button */ existing_session_chooser.set_title (_("Select session file")); existing_session_chooser.signal_file_set().connect (sigc::mem_fun (*this, &ArdourStartup::existing_session_selected)); existing_session_chooser.set_current_folder(poor_mans_glob (Config->get_default_session_parent_dir())); FileFilter session_filter; session_filter.add_pattern ("*.ardour"); session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME)); existing_session_chooser.add_filter (session_filter); existing_session_chooser.set_filter (session_filter); #ifdef GTKOSX existing_session_chooser.add_shortcut_folder ("/Volumes"); #endif Label* browse_label = manage (new Label); browse_label->set_markup (string_compose ("%1", _("Browse for other sessions"))); browse_label->set_alignment (0, 0.5); centering_vbox->pack_start (*browse_label, false, false, 12); centering_vbox->pack_start (existing_session_chooser, false, false); /* pack it all up */ centering_hbox->pack_start (*centering_vbox, true, true); ic_vbox.pack_start (*centering_hbox, true, true); ic_vbox.show_all (); /* user could just click on "Forward" if default * choice is correct. */ set_page_complete (ic_vbox, true); } void ArdourStartup::session_selected () { /* HACK HACK HACK ... change the "Apply" button label to say "Open" */ Gtk::Widget* tl = ic_vbox.get_toplevel(); Gtk::Window* win; if ((win = dynamic_cast(tl)) != 0) { /* ::get_default_widget() is not wrapped in gtkmm */ Gtk::Widget* def = wrap (gtk_window_get_default_widget (win->gobj())); Gtk::Button* button; if ((button = dynamic_cast(def)) != 0) { button->set_label (_("Open")); } } } void ArdourStartup::new_session_button_clicked () { _existing_session_chooser_used = false; recent_session_display.get_selection()->unselect_all (); set_current_page (new_session_page_index); } void ArdourStartup::setup_final_page () { final_page.set_text (string_compose (_("%1 is ready for use"), PROGRAM_NAME)); final_page.show (); final_page_index = append_page (final_page); set_page_complete (final_page, true); set_page_header_image (final_page, icon_pixbuf); set_page_type (final_page, ASSISTANT_PAGE_CONFIRM); } void ArdourStartup::on_cancel () { _response = RESPONSE_CANCEL; gtk_main_quit (); } void ArdourStartup::on_prepare (Gtk::Widget* page) { if (page == &session_new_vbox) { /* if the user already defined a name by using the recent * session list or browsing to an existing session * then we are done. */ bool expect_new_ignored; if (!session_name (expect_new_ignored).empty()) { on_apply (); } } } bool ArdourStartup::on_delete_event (GdkEventAny*) { _response = RESPONSE_CLOSE; gtk_main_quit (); return true; } void ArdourStartup::on_apply () { if (config_modified) { if (default_dir_chooser) { Config->set_default_session_parent_dir (default_dir_chooser->get_filename()); } if (monitor_via_hardware_button.get_active()) { Config->set_monitoring_model (ExternalMonitoring); } else if (monitor_via_ardour_button.get_active()) { Config->set_monitoring_model (SoftwareMonitoring); } Config->set_use_monitor_bus (use_monitor_section_button.get_active()); Config->save_state (); } { /* "touch" the been-here-before path now we've successfully made it through the first time setup (at least) */ ofstream fout (been_here_before_path().c_str()); } _response = RESPONSE_OK; gtk_main_quit (); } void ArdourStartup::populate_session_templates () { vector templates; find_session_templates (templates); template_model->clear (); for (vector::iterator x = templates.begin(); x != templates.end(); ++x) { TreeModel::Row row; row = *(template_model->append ()); row[session_template_columns.name] = (*x).name; row[session_template_columns.path] = (*x).path; } if (!templates.empty()) { /* select first row */ template_chooser.set_active (0); } } void ArdourStartup::setup_new_session_page () { session_new_vbox.set_border_width (12); session_new_vbox.set_spacing (18); VBox *vbox1 = manage (new VBox); HBox* hbox1 = manage (new HBox); Label* label1 = manage (new Label); vbox1->set_spacing (6); hbox1->set_spacing (6); hbox1->pack_start (*label1, false, false); hbox1->pack_start (new_name_entry, true, true); label1->set_text (_("Session name:")); if (!ARDOUR_COMMAND_LINE::session_name.empty()) { new_name_entry.set_text (Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name)); /* name provided - they can move right along */ set_page_complete (session_new_vbox, true); } new_name_entry.signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::new_name_changed)); new_name_entry.signal_activate().connect (sigc::mem_fun (*this, &ArdourStartup::move_along_now)); vbox1->pack_start (*hbox1, true, true); /* --- */ HBox* hbox2 = manage (new HBox); Label* label2 = manage (new Label); hbox2->set_spacing (6); hbox2->pack_start (*label2, false, false); hbox2->pack_start (new_folder_chooser, true, true); label2->set_text (_("Create session folder in:")); if (!ARDOUR_COMMAND_LINE::session_name.empty()) { new_folder_chooser.set_current_folder (poor_mans_glob (Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name))); } else if (ARDOUR_UI::instance()->session_loaded) { // point the new session file chooser at the parent directory of the current session string session_parent_dir = Glib::path_get_dirname(ARDOUR_UI::instance()->the_session()->path()); string::size_type last_dir_sep = session_parent_dir.rfind(G_DIR_SEPARATOR); session_parent_dir = session_parent_dir.substr(0, last_dir_sep); new_folder_chooser.set_current_folder (session_parent_dir); string default_session_folder = poor_mans_glob (Config->get_default_session_parent_dir()); try { /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */ new_folder_chooser.add_shortcut_folder (default_session_folder); } catch (Glib::Error & e) { std::cerr << "new_folder_chooser.add_shortcut_folder (" << default_session_folder << ") threw Glib::Error " << e.what() << std::endl; } } else { new_folder_chooser.set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir())); } new_folder_chooser.show (); new_folder_chooser.set_title (_("Select folder for session")); #ifdef __APPLE__ new_folder_chooser.add_shortcut_folder ("/Volumes"); #endif vbox1->pack_start (*hbox2, false, false); session_new_vbox.pack_start (*vbox1, false, false); /* --- */ VBox *vbox2 = manage (new VBox); HBox* hbox3 = manage (new HBox); template_model = ListStore::create (session_template_columns); vbox2->set_spacing (6); VBox *vbox3 = manage (new VBox); vbox3->set_spacing (6); /* we may want to hide this and show it at various times depending on the existence of templates. */ template_chooser.set_no_show_all (true); use_template_button.set_no_show_all (true); HBox* hbox4a = manage (new HBox); use_template_button.set_label (_("Use this template")); TreeModel::Row row = *template_model->prepend (); row[session_template_columns.name] = (_("no template")); row[session_template_columns.path] = string(); hbox4a->set_spacing (6); hbox4a->pack_start (use_template_button, false, false); hbox4a->pack_start (template_chooser, true, true); template_chooser.set_model (template_model); Gtk::CellRendererText* text_renderer = Gtk::manage (new Gtk::CellRendererText); text_renderer->property_editable() = false; template_chooser.pack_start (*text_renderer); template_chooser.add_attribute (text_renderer->property_text(), session_template_columns.name); template_chooser.set_active (0); vbox3->pack_start (*hbox4a, false, false); /* --- */ if (!new_user) { session_template_chooser.set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir())); HBox* hbox4b = manage (new HBox); use_session_as_template_button.set_label (_("Use an existing session as a template:")); hbox4b->set_spacing (6); hbox4b->pack_start (use_session_as_template_button, false, false); hbox4b->pack_start (session_template_chooser, true, true); use_session_as_template_button.show (); session_template_chooser.show (); Gtk::FileFilter* session_filter = manage (new (Gtk::FileFilter)); session_filter->add_pattern (X_("*.ardour")); session_template_chooser.set_filter (*session_filter); session_template_chooser.set_title (_("Select template")); vbox3->pack_start (*hbox4b, false, false); } /* --- */ HBox* hbox5 = manage (new HBox); hbox5->set_spacing (6); hbox5->pack_start (more_new_session_options_button, false, false); setup_more_options_box (); more_new_session_options_button.add (more_options_vbox); vbox3->pack_start (*hbox5, false, false); hbox3->pack_start (*vbox3, true, true, 8); vbox2->pack_start (*hbox3, false, false); /* --- */ session_new_vbox.pack_start (*vbox2, false, false); session_new_vbox.show_all (); new_session_page_index = append_page (session_new_vbox); set_page_type (session_new_vbox, ASSISTANT_PAGE_CONTENT); set_page_title (session_new_vbox, _("New Session")); set_page_type (session_new_vbox, ASSISTANT_PAGE_CONFIRM); } void ArdourStartup::new_name_changed () { if (!new_name_entry.get_text().empty()) { session_selected (); set_page_complete (session_new_vbox, true); } else { set_page_complete (session_new_vbox, false); } } int ArdourStartup::redisplay_recent_sessions () { std::vector session_directories; RecentSessionsSorter cmp; recent_session_display.set_model (Glib::RefPtr(0)); recent_session_model->clear (); ARDOUR::RecentSessions rs; ARDOUR::read_recent_sessions (rs); if (rs.empty()) { recent_session_display.set_model (recent_session_model); return 0; } // // sort them alphabetically sort (rs.begin(), rs.end(), cmp); for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) { session_directories.push_back ((*i).second); } int session_snapshot_count = 0; for (vector::const_iterator i = session_directories.begin(); i != session_directories.end(); ++i) { std::vector state_file_paths; // now get available states for this session get_state_files_in_directory (*i, state_file_paths); vector* states; vector item; string fullpath = *i; /* remove any trailing / */ if (fullpath[fullpath.length()-1] == '/') { fullpath = fullpath.substr (0, fullpath.length()-1); } /* check whether session still exists */ if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) { /* session doesn't exist */ continue; } /* now get available states for this session */ if ((states = Session::possible_states (fullpath)) == 0) { /* no state file? */ continue; } std::vector state_file_names(get_file_names_no_extension (state_file_paths)); Gtk::TreeModel::Row row = *(recent_session_model->append()); row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath); row[recent_session_columns.fullpath] = fullpath; row[recent_session_columns.tip] = Glib::Markup::escape_text (fullpath); ++session_snapshot_count; if (state_file_names.size() > 1) { // add the children for (std::vector::iterator i2 = state_file_names.begin(); i2 != state_file_names.end(); ++i2) { Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children())); child_row[recent_session_columns.visible_name] = *i2; child_row[recent_session_columns.fullpath] = fullpath; child_row[recent_session_columns.tip] = Glib::Markup::escape_text (fullpath); ++session_snapshot_count; } } } recent_session_display.set_tooltip_column(1); // recent_session_columns.tip recent_session_display.set_model (recent_session_model); return session_snapshot_count; // return rs.size(); } void ArdourStartup::recent_session_row_selected () { if (recent_session_display.get_selection()->count_selected_rows() > 0) { set_page_complete (ic_vbox, true); session_selected (); } else { set_page_complete (ic_vbox, false); } } void ArdourStartup::setup_more_options_box () { more_options_vbox.set_border_width (24); _output_limit_count.set_adjustment (_output_limit_count_adj); _input_limit_count.set_adjustment (_input_limit_count_adj); _master_bus_channel_count.set_adjustment (_master_bus_channel_count_adj); chan_count_label_1.set_text (_("channels")); chan_count_label_3.set_text (_("channels")); chan_count_label_4.set_text (_("channels")); chan_count_label_1.set_alignment(0,0.5); chan_count_label_1.set_padding(0,0); chan_count_label_1.set_line_wrap(false); chan_count_label_3.set_alignment(0,0.5); chan_count_label_3.set_padding(0,0); chan_count_label_3.set_line_wrap(false); chan_count_label_4.set_alignment(0,0.5); chan_count_label_4.set_padding(0,0); chan_count_label_4.set_line_wrap(false); bus_label.set_markup (_("Busses")); input_label.set_markup (_("Inputs")); output_label.set_markup (_("Outputs")); _master_bus_channel_count.set_flags(Gtk::CAN_FOCUS); _master_bus_channel_count.set_update_policy(Gtk::UPDATE_ALWAYS); _master_bus_channel_count.set_numeric(true); _master_bus_channel_count.set_digits(0); _master_bus_channel_count.set_wrap(false); _create_master_bus.set_label (_("Create master bus")); _create_master_bus.set_flags(Gtk::CAN_FOCUS); _create_master_bus.set_relief(Gtk::RELIEF_NORMAL); _create_master_bus.set_mode(true); _create_master_bus.set_active(true); _create_master_bus.set_border_width(0); advanced_table.set_row_spacings(0); advanced_table.set_col_spacings(0); _connect_inputs.set_label (_("Automatically connect to physical inputs")); _connect_inputs.set_flags(Gtk::CAN_FOCUS); _connect_inputs.set_relief(Gtk::RELIEF_NORMAL); _connect_inputs.set_mode(true); _connect_inputs.set_active(Config->get_input_auto_connect() != ManualConnect); _connect_inputs.set_border_width(0); _limit_input_ports.set_label (_("Use only")); _limit_input_ports.set_flags(Gtk::CAN_FOCUS); _limit_input_ports.set_relief(Gtk::RELIEF_NORMAL); _limit_input_ports.set_mode(true); _limit_input_ports.set_sensitive(true); _limit_input_ports.set_border_width(0); _input_limit_count.set_flags(Gtk::CAN_FOCUS); _input_limit_count.set_update_policy(Gtk::UPDATE_ALWAYS); _input_limit_count.set_numeric(true); _input_limit_count.set_digits(0); _input_limit_count.set_wrap(false); _input_limit_count.set_sensitive(false); bus_hbox.pack_start (bus_table, Gtk::PACK_SHRINK, 18); bus_label.set_alignment(0, 0.5); bus_label.set_padding(0,0); bus_label.set_line_wrap(false); bus_label.set_selectable(false); bus_label.set_use_markup(true); bus_frame.set_shadow_type(Gtk::SHADOW_NONE); bus_frame.set_label_align(0,0.5); bus_frame.add(bus_hbox); bus_frame.set_label_widget(bus_label); bus_table.set_row_spacings (0); bus_table.set_col_spacings (0); bus_table.attach (_create_master_bus, 0, 1, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0); bus_table.attach (_master_bus_channel_count, 1, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0); bus_table.attach (chan_count_label_1, 2, 3, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 6, 0); input_port_limit_hbox.pack_start(_limit_input_ports, Gtk::PACK_SHRINK, 6); input_port_limit_hbox.pack_start(_input_limit_count, Gtk::PACK_SHRINK, 0); input_port_limit_hbox.pack_start(chan_count_label_3, Gtk::PACK_SHRINK, 6); input_port_vbox.pack_start(_connect_inputs, Gtk::PACK_SHRINK, 0); input_port_vbox.pack_start(input_port_limit_hbox, Gtk::PACK_EXPAND_PADDING, 0); input_table.set_row_spacings(0); input_table.set_col_spacings(0); input_table.attach(input_port_vbox, 0, 1, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 6, 6); input_hbox.pack_start (input_table, Gtk::PACK_SHRINK, 18); input_label.set_alignment(0, 0.5); input_label.set_padding(0,0); input_label.set_line_wrap(false); input_label.set_selectable(false); input_label.set_use_markup(true); input_frame.set_shadow_type(Gtk::SHADOW_NONE); input_frame.set_label_align(0,0.5); input_frame.add(input_hbox); input_frame.set_label_widget(input_label); _connect_outputs.set_label (_("Automatically connect outputs")); _connect_outputs.set_flags(Gtk::CAN_FOCUS); _connect_outputs.set_relief(Gtk::RELIEF_NORMAL); _connect_outputs.set_mode(true); _connect_outputs.set_active(Config->get_output_auto_connect() != ManualConnect); _connect_outputs.set_border_width(0); _limit_output_ports.set_label (_("Use only")); _limit_output_ports.set_flags(Gtk::CAN_FOCUS); _limit_output_ports.set_relief(Gtk::RELIEF_NORMAL); _limit_output_ports.set_mode(true); _limit_output_ports.set_sensitive(true); _limit_output_ports.set_border_width(0); _output_limit_count.set_flags(Gtk::CAN_FOCUS); _output_limit_count.set_update_policy(Gtk::UPDATE_ALWAYS); _output_limit_count.set_numeric(false); _output_limit_count.set_digits(0); _output_limit_count.set_wrap(false); _output_limit_count.set_sensitive(false); output_port_limit_hbox.pack_start(_limit_output_ports, Gtk::PACK_SHRINK, 6); output_port_limit_hbox.pack_start(_output_limit_count, Gtk::PACK_SHRINK, 0); output_port_limit_hbox.pack_start(chan_count_label_4, Gtk::PACK_SHRINK, 6); _connect_outputs_to_master.set_label (_("... to master bus")); _connect_outputs_to_master.set_flags(Gtk::CAN_FOCUS); _connect_outputs_to_master.set_relief(Gtk::RELIEF_NORMAL); _connect_outputs_to_master.set_mode(true); _connect_outputs_to_master.set_active(Config->get_output_auto_connect() == AutoConnectMaster); _connect_outputs_to_master.set_border_width(0); _connect_outputs_to_master.set_group (connect_outputs_group); _connect_outputs_to_physical.set_group (connect_outputs_group); _connect_outputs_to_physical.set_label (_("... to physical outputs")); _connect_outputs_to_physical.set_flags(Gtk::CAN_FOCUS); _connect_outputs_to_physical.set_relief(Gtk::RELIEF_NORMAL); _connect_outputs_to_physical.set_mode(true); _connect_outputs_to_physical.set_active(Config->get_output_auto_connect() == AutoConnectPhysical); _connect_outputs_to_physical.set_border_width(0); output_conn_vbox.pack_start(_connect_outputs, Gtk::PACK_SHRINK, 0); output_conn_vbox.pack_start(_connect_outputs_to_master, Gtk::PACK_SHRINK, 0); output_conn_vbox.pack_start(_connect_outputs_to_physical, Gtk::PACK_SHRINK, 0); output_vbox.set_border_width(6); output_port_vbox.pack_start(output_port_limit_hbox, Gtk::PACK_SHRINK, 0); output_vbox.pack_start(output_conn_vbox); output_vbox.pack_start(output_port_vbox); output_label.set_alignment(0, 0.5); output_label.set_padding(0,0); output_label.set_line_wrap(false); output_label.set_selectable(false); output_label.set_use_markup(true); output_frame.set_shadow_type(Gtk::SHADOW_NONE); output_frame.set_label_align(0,0.5); output_hbox.pack_start (output_vbox, Gtk::PACK_SHRINK, 18); output_frame.add(output_hbox); output_frame.set_label_widget(output_label); more_options_vbox.pack_start(advanced_table, Gtk::PACK_SHRINK, 0); more_options_vbox.pack_start(bus_frame, Gtk::PACK_SHRINK, 6); more_options_vbox.pack_start(input_frame, Gtk::PACK_SHRINK, 6); more_options_vbox.pack_start(output_frame, Gtk::PACK_SHRINK, 0); /* signals */ _connect_inputs.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::connect_inputs_clicked)); _connect_outputs.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::connect_outputs_clicked)); _limit_input_ports.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::limit_inputs_clicked)); _limit_output_ports.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::limit_outputs_clicked)); _create_master_bus.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::master_bus_button_clicked)); /* note that more_options_vbox is "visible" by default even * though it may not be displayed to the user, this is so the dialog * doesn't resize. */ more_options_vbox.show_all (); } bool ArdourStartup::create_master_bus() const { return _create_master_bus.get_active(); } int ArdourStartup::master_channel_count() const { return _master_bus_channel_count.get_value_as_int(); } bool ArdourStartup::connect_inputs() const { return _connect_inputs.get_active(); } bool ArdourStartup::limit_inputs_used_for_connection() const { return _limit_input_ports.get_active(); } int ArdourStartup::input_limit_count() const { return _input_limit_count.get_value_as_int(); } bool ArdourStartup::connect_outputs() const { return _connect_outputs.get_active(); } bool ArdourStartup::limit_outputs_used_for_connection() const { return _limit_output_ports.get_active(); } int ArdourStartup::output_limit_count() const { return _output_limit_count.get_value_as_int(); } bool ArdourStartup::connect_outs_to_master() const { return _connect_outputs_to_master.get_active(); } bool ArdourStartup::connect_outs_to_physical() const { return _connect_outputs_to_physical.get_active(); } void ArdourStartup::connect_inputs_clicked () { _limit_input_ports.set_sensitive(_connect_inputs.get_active()); if (_connect_inputs.get_active() && _limit_input_ports.get_active()) { _input_limit_count.set_sensitive(true); } else { _input_limit_count.set_sensitive(false); } } void ArdourStartup::connect_outputs_clicked () { bool const co = _connect_outputs.get_active (); _limit_output_ports.set_sensitive(co); _connect_outputs_to_master.set_sensitive(co); _connect_outputs_to_physical.set_sensitive(co); if (co && _limit_output_ports.get_active()) { _output_limit_count.set_sensitive(true); } else { _output_limit_count.set_sensitive(false); } } void ArdourStartup::limit_inputs_clicked () { _input_limit_count.set_sensitive(_limit_input_ports.get_active()); } void ArdourStartup::limit_outputs_clicked () { _output_limit_count.set_sensitive(_limit_output_ports.get_active()); } void ArdourStartup::master_bus_button_clicked () { bool const yn = _create_master_bus.get_active(); _master_bus_channel_count.set_sensitive(yn); _connect_outputs_to_master.set_sensitive(yn); } void ArdourStartup::move_along_now () { on_apply (); } void ArdourStartup::recent_row_activated (const Gtk::TreePath&, Gtk::TreeViewColumn*) { set_page_complete (ic_vbox, true); move_along_now (); } void ArdourStartup::existing_session_selected () { _existing_session_chooser_used = true; session_selected (); set_page_complete (ic_vbox, true); move_along_now (); } std::string ArdourStartup::been_here_before_path () const { // XXXX use more specific version so we can catch upgrades return Glib::build_filename (user_config_directory (), ".a3"); } void ArdourStartup::updates_button_clicked () { //now open a browser window so user can see more PBD::open_uri (Config->get_updates_url()); } bool ArdourStartup::info_scroller_update() { info_scroller_count++; char buf[512]; snprintf (buf, std::min(info_scroller_count,sizeof(buf)-1), "%s", ARDOUR_UI::instance()->announce_string().c_str() ); buf[info_scroller_count] = 0; info_scroller_label.set_text (buf); info_scroller_label.show(); if (info_scroller_count > ARDOUR_UI::instance()->announce_string().length()) { info_scroller_connection.disconnect(); } return true; } void ArdourStartup::on_map () { Gtk::Assistant::on_map (); populate_session_templates (); if (!template_model->children().empty()) { use_template_button.show(); template_chooser.show (); } else { use_template_button.hide(); template_chooser.hide (); } if (recent_session_model) { int cnt = redisplay_recent_sessions (); if (cnt > 0) { recent_scroller.show(); recent_label.show (); if (cnt > 4) { recent_scroller.set_size_request (-1, 300); } } else { recent_scroller.hide(); recent_label.hide (); } } }