reorder ARDOUR_UI action registration and adding tabbables to the main window, to...
[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 "meterbridge.h"
40 #include "luainstance.h"
41 #include "luawindow.h"
42 #include "mixer_ui.h"
43 #include "keyboard.h"
44 #include "keyeditor.h"
45 #include "splash.h"
46 #include "rc_option_editor.h"
47 #include "route_params_ui.h"
48 #include "time_info_box.h"
49 #include "opts.h"
50 #include "utils.h"
51
52 #include "pbd/i18n.h"
53
54 using namespace Gtk;
55 using namespace PBD;
56
57 namespace ARDOUR {
58         class Session;
59         class Route;
60 }
61
62 using namespace ARDOUR;
63 using namespace Gtkmm2ext;
64
65 void
66 ARDOUR_UI::we_have_dependents ()
67 {
68         /* other windows and related key-event-handling contexts have already
69          * called Bindings::get_bindings() to setup their list of keybindings.
70          * Do that here for the global bindings.
71          */
72
73         if ((global_bindings = Bindings::get_bindings (X_("Global"))) == 0) {
74                 error << _("Global keybindings are missing") << endmsg;
75         }
76
77         install_actions ();
78         ProcessorBox::register_actions ();
79
80         /* Global, editor, mixer, processor box actions are defined now. Link
81            them with any bindings, so that GTK does not get a chance to define
82            the GTK accel map entries first when we ask the GtkUIManager to
83            create menus/widgets.
84
85            If GTK adds the actions to its accel map before we do, we lose our
86            freedom to use any keys. More precisely, we can use any keys, but
87            ones that GTK considers illegal as accelerators will not show up in
88            menus.
89
90            There are other dynamic actions that can be created by a monitor
91            section, by step entry dialogs. These need to be handled
92            separately. They don't tend to use GTK-illegal bindings and more
93            importantly they don't have menus showing the bindings, so it is
94            less of an issue.
95         */
96
97         Gtkmm2ext::Bindings::associate_all ();
98
99         editor->setup_tooltips ();
100         editor->UpdateAllTransportClocks.connect (sigc::mem_fun (*this, &ARDOUR_UI::update_transport_clocks));
101
102         /* catch up on tabbable state, in the right order to leave the editor
103          * selected by default
104          */
105
106         tabbable_state_change (*rc_option_editor);
107         tabbable_state_change (*mixer);
108         tabbable_state_change (*editor);
109
110         /* all actions are defined */
111
112         ActionManager::load_menus (ARDOUR_COMMAND_LINE::menus_file);
113
114         /* catch up on parameters */
115
116         boost::function<void (std::string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
117         Config->map_parameters (pc);
118
119         UIConfiguration::instance().reset_dpi ();
120 }
121
122 void
123 ARDOUR_UI::connect_dependents_to_session (ARDOUR::Session *s)
124 {
125         DisplaySuspender ds;
126         BootMessage (_("Setup Editor"));
127         editor->set_session (s);
128         BootMessage (_("Setup Mixer"));
129         mixer->set_session (s);
130         meterbridge->set_session (s);
131         luawindow->set_session (s);
132
133         /* its safe to do this now */
134
135         BootMessage (_("Reload Session History"));
136         s->restore_history ("");
137 }
138
139 /** The main editor window has been closed */
140 gint
141 ARDOUR_UI::exit_on_main_window_close (GdkEventAny * /*ev*/)
142 {
143 #ifdef __APPLE__
144         /* just hide the window, and return - the top menu stays up */
145         editor->hide ();
146         return TRUE;
147 #else
148         /* time to get out of here */
149         finish();
150         return TRUE;
151 #endif
152 }
153
154 GtkNotebook*
155 ARDOUR_UI::tab_window_root_drop (GtkNotebook* src,
156                                  GtkWidget* w,
157                                  gint x,
158                                  gint y,
159                                  gpointer)
160 {
161         using namespace std;
162         Gtk::Notebook* nb = 0;
163         Gtk::Window* win = 0;
164         ArdourWidgets::Tabbable* tabbable = 0;
165
166
167         if (w == GTK_WIDGET(editor->contents().gobj())) {
168                 tabbable = editor;
169         } else if (w == GTK_WIDGET(mixer->contents().gobj())) {
170                 tabbable = mixer;
171         } else if (w == GTK_WIDGET(rc_option_editor->contents().gobj())) {
172                 tabbable = rc_option_editor;
173         } else {
174                 return 0;
175         }
176
177         nb = tabbable->tab_root_drop ();
178         win = tabbable->own_window ();
179
180         if (nb) {
181                 win->move (x, y);
182                 win->show_all ();
183                 win->present ();
184                 return nb->gobj();
185         }
186
187         return 0; /* what was that? */
188 }
189
190 bool
191 ARDOUR_UI::idle_ask_about_quit ()
192 {
193         if (_session && _session->dirty()) {
194                 finish ();
195         } else {
196                 /* no session or session not dirty, but still ask anyway */
197
198                 Gtk::MessageDialog msg (string_compose (_("Quit %1?"), PROGRAM_NAME),
199                                         false, /* no markup */
200                                         Gtk::MESSAGE_INFO,
201                                         Gtk::BUTTONS_YES_NO,
202                                         true); /* modal */
203                 msg.set_default_response (Gtk::RESPONSE_YES);
204
205                 if (msg.run() == Gtk::RESPONSE_YES) {
206                         finish ();
207                 }
208         }
209
210         /* not reached but keep the compiler happy */
211
212         return false;
213 }
214
215 bool
216 ARDOUR_UI::main_window_delete_event (GdkEventAny* ev)
217 {
218         /* quit the application as soon as we go idle. If we call this here,
219          * the window manager/desktop can think we're taking too longer to
220          * handle the "delete" event
221          */
222
223         Glib::signal_idle().connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_ask_about_quit));
224
225         return true;
226 }
227
228 static GtkNotebook*
229 tab_window_root_drop (GtkNotebook* src,
230                       GtkWidget* w,
231                       gint x,
232                       gint y,
233                       gpointer user_data)
234 {
235         return ARDOUR_UI::instance()->tab_window_root_drop (src, w, x, y, user_data);
236 }
237
238 int
239 ARDOUR_UI::setup_windows ()
240 {
241         /* actions do not need to be defined when we load keybindings. They
242          * will be lazily discovered. But bindings do need to exist when we
243          * create windows/tabs with their own binding sets.
244          */
245
246         keyboard->setup_keybindings ();
247
248         _tabs.set_show_border(false);
249         _tabs.signal_switch_page().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_switch));
250         _tabs.signal_page_added().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_page_added));
251         _tabs.signal_page_removed().connect (sigc::mem_fun (*this, &ARDOUR_UI::tabs_page_removed));
252
253         rc_option_editor = new RCOptionEditor;
254         rc_option_editor->StateChange.connect (sigc::mem_fun (*this, &ARDOUR_UI::tabbable_state_change));
255
256         if (create_editor ()) {
257                 error << _("UI: cannot setup editor") << endmsg;
258                 return -1;
259         }
260
261         if (create_mixer ()) {
262                 error << _("UI: cannot setup mixer") << endmsg;
263                 return -1;
264         }
265
266         if (create_meterbridge ()) {
267                 error << _("UI: cannot setup meterbridge") << endmsg;
268                 return -1;
269         }
270
271         if (create_luawindow ()) {
272                 error << _("UI: cannot setup luawindow") << endmsg;
273                 return -1;
274         }
275
276         time_info_box = new TimeInfoBox ("ToolbarTimeInfo", false);
277         /* all other dialogs are created conditionally */
278
279         we_have_dependents ();
280
281         /* order of addition affects order seen in initial window display */
282
283         rc_option_editor->add_to_notebook (_tabs, _("Preferences"));
284         mixer->add_to_notebook (_tabs, _("Mixer"));
285         editor->add_to_notebook (_tabs, _("Editor"));
286
287         top_packer.pack_start (menu_bar_base, false, false);
288
289         main_vpacker.pack_start (top_packer, false, false);
290
291         ArdourWidgets::ArdourDropShadow *spacer = manage (new (ArdourWidgets::ArdourDropShadow));
292         spacer->set_size_request( -1, 4 );
293         spacer->show();
294
295         /* now add the transport sample to the top of main window */
296
297         main_vpacker.pack_start ( *spacer, false, false);
298         main_vpacker.pack_start (transport_frame, false, false);
299         main_vpacker.pack_start (_tabs, true, true);
300
301         LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::update_action_script_btn));
302
303         for (int i = 0; i < MAX_LUA_ACTION_SCRIPTS; ++i) {
304                 std::string const a = string_compose (X_("script-action-%1"), i + 1);
305                 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
306                 assert (act);
307                 action_script_call_btn[i].set_text (string_compose ("%1", i+1));
308                 action_script_call_btn[i].set_related_action (act);
309                 action_script_call_btn[i].signal_button_press_event().connect (sigc::bind (sigc::mem_fun(*this, &ARDOUR_UI::bind_lua_action_script), i), false);
310                 if (act->get_sensitive ()) {
311                         action_script_call_btn[i].set_visual_state (Gtkmm2ext::VisualState (action_script_call_btn[i].visual_state() & ~Gtkmm2ext::Insensitive));
312                 } else {
313                         action_script_call_btn[i].set_visual_state (Gtkmm2ext::VisualState (action_script_call_btn[i].visual_state() | Gtkmm2ext::Insensitive));
314                 }
315                 const int row = i % 2;
316                 const int col = i / 2;
317                 action_script_table.attach (action_script_call_btn[i], col, col + 1, row, row + 1, EXPAND, EXPAND, 1, 0);
318                 action_script_call_btn[i].set_no_show_all ();
319         }
320         action_script_table.show ();
321
322         setup_transport();
323         build_menu_bar ();
324         setup_tooltips ();
325
326         _main_window.signal_delete_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::main_window_delete_event));
327
328         /* pack the main vpacker into the main window and show everything
329          */
330
331         _main_window.add (main_vpacker);
332         transport_frame.show_all ();
333
334         const XMLNode* mnode = main_window_settings ();
335
336         if (mnode) {
337                 XMLProperty const * prop;
338                 gint x = -1;
339                 gint y = -1;
340                 gint w = -1;
341                 gint h = -1;
342
343                 if ((prop = mnode->property (X_("x"))) != 0) {
344                         x = atoi (prop->value());
345                 }
346
347                 if ((prop = mnode->property (X_("y"))) != 0) {
348                         y = atoi (prop->value());
349                 }
350
351                 if ((prop = mnode->property (X_("w"))) != 0) {
352                         w = atoi (prop->value());
353                 }
354
355                 if ((prop = mnode->property (X_("h"))) != 0) {
356                         h = atoi (prop->value());
357                 }
358
359                 if (x >= 0 && y >= 0 && w >= 0 && h >= 0) {
360                         _main_window.set_position (Gtk::WIN_POS_NONE);
361                 }
362
363                 if (x >= 0 && y >= 0) {
364                         _main_window.move (x, y);
365                 }
366
367                 if (w > 0 && h > 0) {
368                         _main_window.set_default_size (w, h);
369                 }
370
371                 std::string current_tab;
372
373                 if ((prop = mnode->property (X_("current-tab"))) != 0) {
374                         current_tab = prop->value();
375                 } else {
376                         current_tab = "editor";
377                 }
378                 if (mixer && current_tab == "mixer") {
379                         _tabs.set_current_page (_tabs.page_num (mixer->contents()));
380                 } else if (rc_option_editor && current_tab == "preferences") {
381                         _tabs.set_current_page (_tabs.page_num (rc_option_editor->contents()));
382                 } else if (editor) {
383                         _tabs.set_current_page (_tabs.page_num (editor->contents()));
384                 }
385         }
386
387         setup_toplevel_window (_main_window, "", this);
388         _main_window.show_all ();
389
390         _tabs.set_show_tabs (false);
391
392         /* It would be nice if Gtkmm had wrapped this rather than just
393          * deprecating the old set_window_creation_hook() method, but oh well...
394          */
395         g_signal_connect (_tabs.gobj(), "create-window", (GCallback) ::tab_window_root_drop, this);
396
397         return 0;
398 }
399
400 bool
401 ARDOUR_UI::bind_lua_action_script (GdkEventButton*ev, int i)
402 {
403         if (ev->button != 3) {
404                 return false;
405         }
406         LuaInstance *li = LuaInstance::instance();
407         if (Gtkmm2ext::Keyboard::modifier_state_equals (ev->state, Gtkmm2ext::Keyboard::TertiaryModifier)) {
408                 li->remove_lua_action (i);
409         } else {
410                 li->interactive_add (LuaScriptInfo::EditorAction, i);
411         }
412         return true;
413 }
414
415 void
416 ARDOUR_UI::update_action_script_btn (int i, const std::string& n)
417 {
418         if (LuaInstance::instance()->lua_action_has_icon (i)) {
419                 uintptr_t ii = i;
420                 action_script_call_btn[i].set_icon (&LuaInstance::render_action_icon, (void*)ii);
421         } else {
422                 action_script_call_btn[i].set_icon (0, 0);
423         }
424
425         std::string const a = string_compose (X_("script-action-%1"), i + 1);
426         Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
427         assert (act);
428         if (n.empty ()) {
429                 act->set_label (string_compose (_("Unset #%1"), i + 1));
430                 act->set_tooltip (_("No action bound\nRight-click to assign"));
431                 act->set_sensitive (false);
432         } else {
433                 act->set_label (n);
434                 act->set_tooltip (string_compose (_("%1\n\nClick to run\nRight-click to re-assign\nShift+right-click to unassign"), n));
435                 act->set_sensitive (true);
436         }
437         KeyEditor::UpdateBindings ();
438 }