most of the changes required to add a new master faders tabbable
[ardour.git] / gtk2_ardour / ardour_ui_dependents.cc
1 /*
2     Copyright (C) 2000 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 /* this file exists solely to break compilation dependencies that
25    would connect changes to the mixer or editor objects.
26 */
27
28 #include <cstdio>
29
30 #include "pbd/error.h"
31
32 #include "ardour/session.h"
33
34 #include "gtkmm2ext/bindings.h"
35
36 #include "actions.h"
37 #include "ardour_ui.h"
38 #include "public_editor.h"
39 #include "master_faders.h"
40 #include "meterbridge.h"
41 #include "luawindow.h"
42 #include "mixer_ui.h"
43 #include "keyboard.h"
44 #include "splash.h"
45 #include "rc_option_editor.h"
46 #include "route_params_ui.h"
47 #include "opts.h"
48 #include "utils.h"
49
50 #include "i18n.h"
51
52 using namespace Gtk;
53 using namespace PBD;
54
55 namespace ARDOUR {
56         class Session;
57         class Route;
58 }
59
60 using namespace ARDOUR;
61
62 void
63 ARDOUR_UI::we_have_dependents ()
64 {
65         install_actions ();
66         load_bindings ();
67
68         ProcessorBox::register_actions ();
69
70         /* Global, editor, mixer, processor box actions are defined now. Link
71            them with any bindings, so that GTK does not get a chance to define
72            the GTK accel map entries first when we ask the GtkUIManager to
73            create menus/widgets.
74
75            If GTK adds the actions to its accel map before we do, we lose our
76            freedom to use any keys. More precisely, we can use any keys, but
77            ones that GTK considers illegal as accelerators will not show up in
78            menus.
79
80            There are other dynamic actions that can be created by a monitor
81            section, by step entry dialogs. These need to be handled
82            separately. They don't tend to use GTK-illegal bindings and more
83            importantly they don't have menus showing the bindings, so it is
84            less of an issue.
85         */
86
87         Gtkmm2ext::Bindings::associate_all ();
88
89         editor->setup_tooltips ();
90         editor->UpdateAllTransportClocks.connect (sigc::mem_fun (*this, &ARDOUR_UI::update_transport_clocks));
91
92         /* catch up on tabbable state, in the right order to leave the editor
93          * selected by default
94          */
95
96         tabbable_state_change (*rc_option_editor);
97         tabbable_state_change (*mixer);
98         tabbable_state_change (*editor);
99
100         /* all actions are defined */
101
102         ActionManager::load_menus (ARDOUR_COMMAND_LINE::menus_file);
103
104         editor->track_mixer_selection ();
105         mixer->track_editor_selection ();
106
107         /* catch up on parameters */
108
109         boost::function<void (std::string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
110         Config->map_parameters (pc);
111
112         UIConfiguration::instance().reset_dpi ();
113 }
114
115 void
116 ARDOUR_UI::connect_dependents_to_session (ARDOUR::Session *s)
117 {
118         DisplaySuspender ds;
119         BootMessage (_("Setup Editor"));
120         editor->set_session (s);
121         BootMessage (_("Setup Mixer"));
122         mixer->set_session (s);
123         meterbridge->set_session (s);
124         luawindow->set_session (s);
125
126         /* its safe to do this now */
127
128         BootMessage (_("Reload Session History"));
129         s->restore_history ("");
130 }
131
132 /** The main editor window has been closed */
133 gint
134 ARDOUR_UI::exit_on_main_window_close (GdkEventAny * /*ev*/)
135 {
136 #ifdef TOP_MENUBAR
137         /* just hide the window, and return - the top menu stays up */
138         editor->hide ();
139         return TRUE;
140 #else
141         /* time to get out of here */
142         finish();
143         return TRUE;
144 #endif
145 }
146
147 GtkNotebook*
148 ARDOUR_UI::tab_window_root_drop (GtkNotebook* src,
149                                  GtkWidget* w,
150                                  gint x,
151                                  gint y,
152                                  gpointer)
153 {
154         using namespace std;
155         Gtk::Notebook* nb = 0;
156         Gtk::Window* win = 0;
157         Gtkmm2ext::Tabbable* tabbable = 0;
158
159
160         if (w == GTK_WIDGET(editor->contents().gobj())) {
161                 tabbable = editor;
162         } else if (w == GTK_WIDGET(mixer->contents().gobj())) {
163                 tabbable = mixer;
164         } else if (w == GTK_WIDGET(rc_option_editor->contents().gobj())) {
165                 tabbable = rc_option_editor;
166         } else if (w == GTK_WIDGET(masters->contents().gobj())) {
167                 tabbable = masters;
168                 return 0;
169         }
170
171         nb = tabbable->tab_root_drop ();
172         win = tabbable->own_window ();
173
174         if (nb) {
175                 win->move (x, y);
176                 win->show_all ();
177                 win->present ();
178                 return nb->gobj();
179         }
180
181         return 0; /* what was that? */
182 }
183
184 bool
185 ARDOUR_UI::idle_ask_about_quit ()
186 {
187         if (_session && _session->dirty()) {
188                 finish ();
189         } else {
190                 /* no session or session not dirty, but still ask anyway */
191
192                 Gtk::MessageDialog msg (string_compose ("Quit %1?", PROGRAM_NAME),
193                                         false, /* no markup */
194                                         Gtk::MESSAGE_INFO,
195                                         Gtk::BUTTONS_YES_NO,
196                                         true); /* modal */
197                 msg.set_default_response (Gtk::RESPONSE_YES);
198
199                 if (msg.run() == Gtk::RESPONSE_YES) {
200                         finish ();
201                 }
202         }
203
204         /* not reached but keep the compiler happy */
205
206         return false;
207 }
208
209 bool
210 ARDOUR_UI::main_window_delete_event (GdkEventAny* ev)
211 {
212         /* quit the application as soon as we go idle. If we call this here,
213          * the window manager/desktop can think we're taking too longer to
214          * handle the "delete" event
215          */
216
217         Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_ask_about_quit));
218
219         return true;
220 }
221
222 static GtkNotebook*
223 tab_window_root_drop (GtkNotebook* src,
224                       GtkWidget* w,
225                       gint x,
226                       gint y,
227                       gpointer user_data)
228 {
229         return ARDOUR_UI::instance()->tab_window_root_drop (src, w, x, y, user_data);
230 }
231
232 int
233 ARDOUR_UI::setup_windows ()
234 {
235         /* actions do not need to be defined when we load keybindings. They
236          * will be lazily discovered. But bindings do need to exist when we
237          * create windows/tabs with their own binding sets.
238          */
239
240         keyboard->setup_keybindings ();
241
242         _tabs.signal_switch_page().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_switch));
243         _tabs.signal_page_added().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_page_added));
244         _tabs.signal_page_removed().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_page_removed));
245
246         rc_option_editor = new RCOptionEditor;
247         rc_option_editor->StateChange.connect (sigc::mem_fun (*this, &ARDOUR_UI::tabbable_state_change));
248
249         if (create_editor ()) {
250                 error << _("UI: cannot setup editor") << endmsg;
251                 return -1;
252         }
253
254         if (create_mixer ()) {
255                 error << _("UI: cannot setup mixer") << endmsg;
256                 return -1;
257         }
258
259         if (create_meterbridge ()) {
260                 error << _("UI: cannot setup meterbridge") << endmsg;
261                 return -1;
262         }
263
264         if (create_luawindow ()) {
265                 error << _("UI: cannot setup luawindow") << endmsg;
266                 return -1;
267         }
268
269         if (create_masters()) {
270                 error << _("UI: cannot setup meterbridge") << endmsg;
271                 return -1;
272         }
273
274         /* order of addition affects order seen in initial window display */
275
276         masters->add_to_notebook (_tabs, _("Masters"));
277         rc_option_editor->add_to_notebook (_tabs, _("Preferences"));
278         mixer->add_to_notebook (_tabs, _("Mixer"));
279         editor->add_to_notebook (_tabs, _("Editor"));
280
281         /* all other dialogs are created conditionally */
282
283         we_have_dependents ();
284
285 #ifdef TOP_MENUBAR
286         EventBox* status_bar_event_box = manage (new EventBox);
287
288         status_bar_event_box->add (status_bar_label);
289         status_bar_event_box->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
290         status_bar_label.set_size_request (300, -1);
291
292         status_bar_label.show ();
293         status_bar_event_box->show ();
294
295         status_bar_event_box->signal_button_press_event().connect (mem_fun (*this, &ARDOUR_UI::status_bar_button_press));
296
297         status_bar_hpacker.pack_start (*status_bar_event_box, true, true, 6);
298         status_bar_hpacker.pack_start (menu_bar_base, false, false, 2);
299 #else
300         top_packer.pack_start (menu_bar_base, false, false);
301 #endif
302
303         main_vpacker.pack_start (top_packer, false, false);
304
305         /* now add the transport frame to the top of main window */
306
307         main_vpacker.pack_start (transport_frame, false, false);
308         main_vpacker.pack_start (_tabs, true, true);
309
310 #ifdef TOP_MENUBAR
311         main_vpacker.pack_start (status_bar_hpacker, false, false);
312 #endif
313
314         for (int i = 0; i < 9; ++i) {
315                 std::string const a = string_compose (X_("script-action-%1"), i + 1);
316                 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
317                 assert (act);
318                 action_script_call_btn[i].set_text (string_compose ("%1", i+1));
319                 action_script_call_btn[i].set_related_action (act);
320                 if (act->get_sensitive ()) {
321                         action_script_call_btn[i].set_visual_state (Gtkmm2ext::VisualState (action_script_call_btn[i].visual_state() & ~Gtkmm2ext::Insensitive));
322                 } else {
323                         action_script_call_btn[i].set_visual_state (Gtkmm2ext::VisualState (action_script_call_btn[i].visual_state() | Gtkmm2ext::Insensitive));
324                 }
325                 const int row = i % 3;
326                 const int col = i / 3;
327                 action_script_table.attach (action_script_call_btn[i], col, col + 1, row, row + 1, EXPAND, EXPAND, 1, 1);
328                 action_script_call_btn[i].set_no_show_all ();
329         }
330         action_script_table.show ();
331
332         setup_transport();
333         build_menu_bar ();
334         setup_tooltips ();
335
336         _main_window.signal_delete_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::main_window_delete_event));
337
338         /* pack the main vpacker into the main window and show everything
339          */
340
341         _main_window.add (main_vpacker);
342         transport_frame.show_all ();
343
344         const XMLNode* mnode = main_window_settings ();
345
346         if (mnode) {
347                 XMLProperty const * prop;
348                 gint x = -1;
349                 gint y = -1;
350                 gint w = -1;
351                 gint h = -1;
352
353                 if ((prop = mnode->property (X_("x"))) != 0) {
354                         x = atoi (prop->value());
355                 }
356
357                 if ((prop = mnode->property (X_("y"))) != 0) {
358                         y = atoi (prop->value());
359                 }
360
361                 if ((prop = mnode->property (X_("w"))) != 0) {
362                         w = atoi (prop->value());
363                 }
364
365                 if ((prop = mnode->property (X_("h"))) != 0) {
366                         h = atoi (prop->value());
367                 }
368
369                 if (x >= 0 && y >= 0 && w >= 0 && h >= 0) {
370                         _main_window.set_position (Gtk::WIN_POS_NONE);
371                 }
372
373                 if (x >= 0 && y >= 0) {
374                         _main_window.move (x, y);
375                 }
376
377                 if (w > 0 && h > 0) {
378                         _main_window.set_default_size (w, h);
379                 }
380
381                 std::string current_tab;
382
383                 if ((prop = mnode->property (X_("current-tab"))) != 0) {
384                         current_tab = prop->value();
385                 } else {
386                         current_tab = "editor";
387                 }
388                 if (mixer && current_tab == "mixer") {
389                         _tabs.set_current_page (_tabs.page_num (mixer->contents()));
390                 } else if (rc_option_editor && current_tab == "preferences") {
391                         _tabs.set_current_page (_tabs.page_num (rc_option_editor->contents()));
392                 } else if (masters && current_tab == "masters") {
393                         _tabs.set_current_page (_tabs.page_num (masters->contents()));
394                 } else if (editor) {
395                         _tabs.set_current_page (_tabs.page_num (editor->contents()));
396                 }
397         }
398
399         setup_toplevel_window (_main_window, "", this);
400         _main_window.show_all ();
401
402         _tabs.set_show_tabs (false);
403
404         /* It would be nice if Gtkmm had wrapped this rather than just
405          * deprecating the old set_window_creation_hook() method, but oh well...
406          */
407         g_signal_connect (_tabs.gobj(), "create-window", (GCallback) ::tab_window_root_drop, this);
408
409         return 0;
410 }