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