Merge branch 'master' into saveas
[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 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
23 #endif
24
25 #include <fstream>
26 #include <algorithm>
27
28 #include <gtkmm/main.h>
29 #include <gtkmm/filechooser.h>
30
31 #include "pbd/failed_constructor.h"
32 #include "pbd/file_utils.h"
33 #include "pbd/replace_all.h"
34 #include "pbd/whitespace.h"
35 #include "pbd/stacktrace.h"
36 #include "pbd/openuri.h"
37
38 #include "ardour/audioengine.h"
39 #include "ardour/filesystem_paths.h"
40 #include "ardour/recent_sessions.h"
41 #include "ardour/session.h"
42 #include "ardour/session_state_utils.h"
43 #include "ardour/template_utils.h"
44 #include "ardour/filename_extensions.h"
45
46 #include "ardour_ui.h"
47 #include "startup.h"
48 #include "opts.h"
49 #include "engine_dialog.h"
50 #include "i18n.h"
51 #include "utils.h"
52
53 using namespace std;
54 using namespace Gtk;
55 using namespace Gdk;
56 using namespace Glib;
57 using namespace PBD;
58 using namespace ARDOUR;
59 using namespace ARDOUR_UI_UTILS;
60
61 ArdourStartup* ArdourStartup::the_startup = 0;
62
63 ArdourStartup::ArdourStartup ()
64         : _response (RESPONSE_OK)
65         , config_modified (false)
66         , default_dir_chooser (0)
67         , monitor_via_hardware_button (string_compose (_("Use an external mixer or the hardware mixer of your audio interface.\n"
68                                                          "%1 will play NO role in monitoring"), PROGRAM_NAME))
69         , monitor_via_ardour_button (string_compose (_("Ask %1 to play back material as it is being recorded"), PROGRAM_NAME))
70         , audio_page_index (-1)
71         , new_user_page_index (-1)
72         , default_folder_page_index (-1)
73         , monitoring_page_index (-1)
74         , final_page_index (-1)
75 {
76         set_position (WIN_POS_CENTER);
77         set_border_width (12);
78         
79         if ((icon_pixbuf = ::get_icon ("ardour_icon_48px")) == 0) {
80                 throw failed_constructor();
81         }
82         
83         list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
84         Glib::RefPtr<Gdk::Pixbuf> icon;
85         
86         if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
87                 window_icons.push_back (icon);
88         }
89         if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
90                 window_icons.push_back (icon);
91         }
92         if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
93                 window_icons.push_back (icon);
94         }
95         if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
96                 window_icons.push_back (icon);
97         }
98         if (!window_icons.empty ()) {
99                 set_default_icon_list (window_icons);
100         }
101         
102         setup_new_user_page ();
103         setup_first_time_config_page ();
104         setup_monitoring_choice_page ();
105         setup_monitor_section_choice_page ();
106         setup_final_page ();
107
108         the_startup = this;
109 }
110
111 ArdourStartup::~ArdourStartup ()
112 {
113 }
114
115 bool
116 ArdourStartup::required ()
117 {
118         /* look for a "been here before" file for this version or earlier
119          * versions
120          */
121
122         const int current_version = atoi (PROGRAM_VERSION);
123         
124         for (int v = current_version; v != 0; --v) {
125                 if (Glib::file_test (ARDOUR::been_here_before_path (v), Glib::FILE_TEST_EXISTS)) {
126                         if (v != current_version) {
127                                 /* older version exists, create the current one */
128                                 ofstream fout (been_here_before_path (current_version).c_str());
129                         }
130                         return false;
131                 }
132         }
133
134         return true;
135 }
136
137 void
138 ArdourStartup::setup_new_user_page ()
139 {
140         Label* foomatic = manage (new Label);
141
142         foomatic->set_markup (string_compose (_("\
143 <span size=\"larger\">%1 is a digital audio workstation. You can use it to \
144 record, edit and mix multi-track audio. You can produce your \
145 own CDs, mix video soundtracks, or experiment with new \
146 ideas about music and sound. \
147 \n\n\
148 There are a few things that need to be configured before you start \
149 using the program.</span> \
150 "), PROGRAM_NAME));
151         foomatic->set_justify (JUSTIFY_FILL);
152         foomatic->set_line_wrap ();
153
154         HBox* hbox = manage (new HBox);
155         HBox* vbox = manage (new HBox);
156
157         vbox->set_border_width (24);
158
159         hbox->pack_start (*foomatic, true, true);
160         vbox->pack_start (*hbox, true, true);
161
162         foomatic->show ();
163         hbox->show ();
164         vbox->show ();
165
166         new_user_page_index = append_page (*vbox);
167         set_page_type (*vbox, ASSISTANT_PAGE_INTRO);
168         set_page_title (*vbox, string_compose (_("Welcome to %1"), PROGRAM_NAME));
169         set_page_header_image (*vbox, icon_pixbuf);
170         set_page_complete (*vbox, true);
171 }
172
173 void
174 ArdourStartup::default_dir_changed ()
175 {
176         Config->set_default_session_parent_dir (default_dir_chooser->get_filename());
177         // make new session folder chooser point to the new default
178         new_folder_chooser.set_current_folder (Config->get_default_session_parent_dir());       
179         config_changed ();
180 }
181
182 void
183 ArdourStartup::config_changed ()
184 {
185         config_modified = true;
186 }
187
188 void
189 ArdourStartup::setup_first_time_config_page ()
190 {
191         default_dir_chooser = manage (new FileChooserButton (string_compose (_("Default folder for %1 sessions"), PROGRAM_NAME),
192                                                              FILE_CHOOSER_ACTION_SELECT_FOLDER));
193         Gtk::Label* txt = manage (new Label);
194         HBox* hbox = manage (new HBox);
195         VBox* vbox = manage (new VBox);
196
197         txt->set_markup (string_compose (_("\
198 Each project that you work on with %1 has its own folder.\n\
199 These can require a lot of disk space if you are recording audio.\n\
200 \n\
201 Where would you like new %1 sessions to be stored by default?\n\n\
202 <i>(You can put new sessions anywhere, this is just a default)</i>"), PROGRAM_NAME));
203         txt->set_alignment (0.0, 0.0);
204
205         vbox->set_spacing (18);
206         vbox->set_border_width (24);
207
208         hbox->pack_start (*default_dir_chooser, false, true, 8);
209         vbox->pack_start (*txt, false, false);
210         vbox->pack_start (*hbox, false, true);
211
212         cerr << "set default folder to " << poor_mans_glob (Config->get_default_session_parent_dir()) << endl;
213         default_dir_chooser->set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir()));
214         default_dir_chooser->signal_current_folder_changed().connect (sigc::mem_fun (*this, &ArdourStartup::default_dir_changed));
215         default_dir_chooser->show ();
216
217         vbox->show_all ();
218
219         default_folder_page_index = append_page (*vbox);
220         set_page_title (*vbox, _("Default folder for new sessions"));
221         set_page_header_image (*vbox, icon_pixbuf);
222         set_page_type (*vbox, ASSISTANT_PAGE_CONTENT);
223
224         /* user can just skip all these settings if they want to */
225
226         set_page_complete (*vbox, true);
227 }
228
229 void
230 ArdourStartup::setup_monitoring_choice_page ()
231 {
232         mon_vbox.set_spacing (18);
233         mon_vbox.set_border_width (24);
234
235         HBox* hbox = manage (new HBox);
236         VBox* vbox = manage (new VBox);
237         /* first button will be on by default */
238         RadioButton::Group g (monitor_via_ardour_button.get_group());
239         monitor_via_hardware_button.set_group (g);
240
241         monitor_label.set_markup(_("\
242 While recording instruments or vocals, you probably want to listen to the\n\
243 signal as well as record it. This is called \"monitoring\". There are\n\
244 different ways to do this depending on the equipment you have and the\n\
245 configuration of that equipment. The two most common are presented here.\n\
246 Please choose whichever one is right for your setup.\n\n\
247 <i>(You can change this preference at any time, via the Preferences dialog)</i>\n\n\
248 <i>If you do not understand what this is about, just accept the default.</i>"));
249         monitor_label.set_alignment (0.0, 0.0);
250
251         vbox->set_spacing (6);
252
253         vbox->pack_start (monitor_via_hardware_button, false, true);
254         vbox->pack_start (monitor_via_ardour_button, false, true);
255         hbox->pack_start (*vbox, true, true, 8);
256         mon_vbox.pack_start (monitor_label, false, false);
257         mon_vbox.pack_start (*hbox, false, false);
258
259         mon_vbox.show_all ();
260
261         monitoring_page_index = append_page (mon_vbox);
262         set_page_title (mon_vbox, _("Monitoring Choices"));
263         set_page_header_image (mon_vbox, icon_pixbuf);
264
265         /* user could just click on "Forward" if default
266          * choice is correct.
267          */
268
269         set_page_complete (mon_vbox, true);
270 }
271
272 void
273 ArdourStartup::setup_monitor_section_choice_page ()
274 {
275         mon_sec_vbox.set_spacing (18);
276         mon_sec_vbox.set_border_width (24);
277
278         HBox* hbox = manage (new HBox);
279         VBox* main_vbox = manage (new VBox);
280         VBox* vbox;
281         Label* l = manage (new Label);
282
283         main_vbox->set_spacing (32);
284
285         no_monitor_section_button.set_label (_("Use a Master bus directly"));
286         l->set_alignment (0.0, 1.0);
287         l->set_markup(_("Connect the Master bus directly to your hardware outputs. This is preferable for simple usage."));
288
289         vbox = manage (new VBox);
290         vbox->set_spacing (6);
291         vbox->pack_start (no_monitor_section_button, false, true);
292         vbox->pack_start (*l, false, true);
293
294         main_vbox->pack_start (*vbox, false, false);
295
296         use_monitor_section_button.set_label (_("Use an additional Monitor bus"));
297         l = manage (new Label);
298         l->set_alignment (0.0, 1.0);
299         l->set_text (_("Use a Monitor bus between Master bus and hardware outputs for \n\
300 greater control in monitoring without affecting the mix."));
301
302         vbox = manage (new VBox);
303         vbox->set_spacing (6);
304         vbox->pack_start (use_monitor_section_button, false, true);
305         vbox->pack_start (*l, false, true);
306
307         main_vbox->pack_start (*vbox, false, false);
308
309         RadioButton::Group g (use_monitor_section_button.get_group());
310         no_monitor_section_button.set_group (g);
311
312         if (Config->get_use_monitor_bus()) {
313                 use_monitor_section_button.set_active (true);
314         } else {
315                 no_monitor_section_button.set_active (true);
316         }
317
318         use_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &ArdourStartup::config_changed));
319         no_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &ArdourStartup::config_changed));
320
321         monitor_section_label.set_markup(_("<i>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.</i>\n\n\
322 <i>If you do not understand what this is about, just accept the default.</i>"));
323         monitor_section_label.set_alignment (0.0, 0.0);
324
325         hbox->pack_start (*main_vbox, true, true, 8);
326         mon_sec_vbox.pack_start (*hbox, false, false);
327         mon_sec_vbox.pack_start (monitor_section_label, false, false);
328
329         mon_sec_vbox.show_all ();
330
331         monitor_section_page_index = append_page (mon_sec_vbox);
332         set_page_title (mon_sec_vbox, _("Monitor Section"));
333         set_page_header_image (mon_sec_vbox, icon_pixbuf);
334
335         /* user could just click on "Forward" if default
336          * choice is correct.
337          */
338
339         set_page_complete (mon_sec_vbox, true);
340 }
341
342 void
343 ArdourStartup::setup_final_page ()
344 {
345         string msg = string_compose (_("%1 is ready for use"), PROGRAM_NAME);
346         
347         final_page.set_markup (string_compose ("<span weight=\"bold\" size=\"large\">%1</span>", msg));
348         final_page.show ();
349         final_page_index = append_page (final_page);
350         set_page_complete (final_page, true);
351         set_page_header_image (final_page, icon_pixbuf);
352         set_page_type (final_page, ASSISTANT_PAGE_CONFIRM);
353 }
354
355 void
356 ArdourStartup::on_cancel ()
357 {
358         _response = RESPONSE_CANCEL;
359         gtk_main_quit ();
360 }
361
362 bool
363 ArdourStartup::on_delete_event (GdkEventAny*)
364 {
365         _response = RESPONSE_CLOSE;
366         gtk_main_quit ();
367         return true;
368 }
369
370 void
371 ArdourStartup::on_apply ()
372 {
373         /* file-chooser button does not emit 'current_folder_changed' signal
374          * when a folder from the dropdown or the sidebar is chosen.
375          * -> explicitly poll for the dir as suggested by the gtk documentation.
376          */
377         if (default_dir_chooser && default_dir_chooser->get_filename() != Config->get_default_session_parent_dir ()) {
378                 config_modified = true;
379         }
380
381         if (config_modified) {
382
383                 if (default_dir_chooser) {
384                         Config->set_default_session_parent_dir (default_dir_chooser->get_filename());
385                 }
386
387                 if (monitor_via_hardware_button.get_active()) {
388                         Config->set_monitoring_model (ExternalMonitoring);
389                 } else if (monitor_via_ardour_button.get_active()) {
390                         Config->set_monitoring_model (SoftwareMonitoring);
391                 }
392
393                 Config->set_use_monitor_bus (use_monitor_section_button.get_active());
394
395                 Config->save_state ();
396
397         }
398
399         {
400                 /* "touch" the been-here-before path now we've successfully
401                    made it through the first time setup (at least)
402                 */
403                 ofstream fout (been_here_before_path().c_str());
404
405         }
406                 
407         _response = RESPONSE_OK;
408         gtk_main_quit ();
409 }
410
411
412 void
413 ArdourStartup::move_along_now ()
414 {
415         on_apply ();
416 }