rename all GTK signals
[ardour.git] / gtk2_ardour / route_params_ui.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     $Id$
19 */
20
21 #include <algorithm>
22
23 #include <pbd/lockmonitor.h>
24 #include <gtkmm2ext/utils.h>
25 #include <gtkmm2ext/stop_signal.h>
26
27 #include <ardour/session.h>
28 #include <ardour/session_route.h>
29 #include <ardour/diskstream.h>
30 #include <ardour/plugin.h>
31 #include <ardour/plugin_manager.h>
32 #include <ardour/ardour.h>
33 #include <ardour/session.h>
34 #include <ardour/route.h>
35 #include <ardour/audio_track.h>
36 #include <ardour/send.h>
37 #include <ardour/insert.h>
38 #include <ardour/connection.h>
39 #include <ardour/session_connection.h>
40
41 #include "route_params_ui.h"
42 #include "keyboard.h"
43 #include "mixer_strip.h"
44 #include "plugin_selector.h"
45 #include "ardour_ui.h"
46 #include "plugin_ui.h"
47 #include "io_selector.h"
48 #include "send_ui.h"
49 #include "utils.h"
50 #include "gui_thread.h"
51
52 #include "i18n.h"
53
54 using namespace ARDOUR;
55 using namespace Gtk;
56 using namespace sigc;
57
58 static const gchar *route_display_titles[] = { N_("Tracks/Buses"), 0 };
59 static const gchar *pre_display_titles[] = { N_("Pre Redirects"), 0 };
60 static const gchar *post_display_titles[] = { N_("Post Redirects"), 0 };
61
62 RouteParams_UI::RouteParams_UI (AudioEngine& eng)
63         : ArdourDialog ("track/bus inspector"),
64           engine (eng),
65           route_select_list (internationalize(route_display_titles)),
66           _route(0), 
67           track_menu(0)
68 {
69         pre_redirect_box = 0;
70         post_redirect_box = 0;
71         _route = 0;
72         _pre_redirect = 0;
73         _post_redirect = 0;
74         _input_iosel = 0;
75         _output_iosel = 0;
76         _active_pre_view = 0;
77         _active_post_view = 0;
78         
79         using namespace Notebook_Helpers;
80
81         input_frame.set_shadow_type(GTK_SHADOW_NONE);
82         output_frame.set_shadow_type(GTK_SHADOW_NONE);
83         
84         notebook.set_show_tabs (true);
85         notebook.set_show_border (true);
86         notebook.set_name ("RouteParamNotebook");
87         
88         route_select_list.column_titles_active();
89         route_select_list.set_name ("RouteParamsListDisplay");
90         route_select_list.set_shadow_type (Gtk::SHADOW_IN);
91         route_select_list.set_selection_mode (GTK_SELECTION_SINGLE);
92         route_select_list.set_reorderable (false);
93         route_select_list.set_size_request (75, -1);
94         route_select_scroller.add (route_select_list);
95         route_select_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
96
97         route_select_frame.set_name("RouteSelectBaseFrame");
98         route_select_frame.set_shadow_type (Gtk::SHADOW_IN);
99         route_select_frame.add(route_select_scroller);
100
101         list_vpacker.pack_start (route_select_frame, true, true);
102         
103         notebook.pages().push_back (TabElem (input_frame, _("Inputs")));
104         notebook.pages().push_back (TabElem (output_frame, _("Outputs")));
105         notebook.pages().push_back (TabElem (pre_redir_hpane, _("Pre-fader Redirects")));
106         notebook.pages().push_back (TabElem (post_redir_hpane, _("Post-fader Redirects")));
107
108         notebook.set_name ("InspectorNotebook");
109         
110         title_label.set_name ("RouteParamsTitleLabel");
111         update_title();
112         
113         // changeable area
114         route_param_frame.set_name("RouteParamsBaseFrame");
115         route_param_frame.set_shadow_type (Gtk::SHADOW_IN);
116         
117         
118         route_hpacker.pack_start (notebook, true, true);
119         
120         
121         route_vpacker.pack_start (title_label, false, false);
122         route_vpacker.pack_start (route_hpacker, true, true);
123
124         
125         list_hpane.add1 (list_vpacker);
126         list_hpane.add2 (route_vpacker);
127
128         list_hpane.set_position(110);
129
130         pre_redir_hpane.set_position(110);
131         post_redir_hpane.set_position(110);
132         
133         global_vpacker.pack_start (list_hpane, true, true);
134         
135         add (global_vpacker);
136         set_name ("RouteParamsWindow");
137         set_default_size (620,370);
138         set_title (_("ardour: track/bus inspector"));
139         set_wmclass (_("ardour_route_parameters"), "Ardour");
140
141         // events
142         route_select_list.select_row.connect (mem_fun(*this, &RouteParams_UI::route_selected));
143         route_select_list.unselect_row.connect (mem_fun(*this, &RouteParams_UI::route_unselected));
144         route_select_list.click_column.connect (mem_fun(*this, &RouteParams_UI::show_track_menu));
145
146
147         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::BUTTON_RELEASE_MASK);
148         
149         _plugin_selector = new PluginSelector (PluginManager::the_manager());
150         _plugin_selector->signal_delete_event.connect (bind (ptr_fun (just_hide_it), 
151                                                      static_cast<Window *> (_plugin_selector)));
152
153
154         delete_event.connect (bind (ptr_fun (just_hide_it), static_cast<Gtk::Window*> (this)));
155 }
156
157 RouteParams_UI::~RouteParams_UI ()
158 {
159 }
160
161 void
162 RouteParams_UI::add_route (Route* route)
163 {
164         ENSURE_GUI_THREAD(bind (mem_fun(*this, &RouteParams_UI::add_route), route));
165         
166         if (route->hidden()) {
167                 return;
168         }
169
170         const gchar *rowdata[1];
171         rowdata[0] = route->name().c_str();
172         route_select_list.rows().push_back (rowdata);
173         route_select_list.rows().back().set_data (route);
174         //route_select_list.rows().back().select ();
175         
176         route->name_changed.connect (bind (mem_fun(*this, &RouteParams_UI::route_name_changed), route));
177         route->GoingAway.connect (bind (mem_fun(*this, &RouteParams_UI::route_removed), route));
178 }
179
180
181 void
182 RouteParams_UI::route_name_changed (void *src, Route *route)
183 {
184         ENSURE_GUI_THREAD(bind (mem_fun(*this, &RouteParams_UI::route_name_changed), src, route));
185         
186         CList_Helpers::RowList::iterator i;
187
188         if ((i = route_select_list.rows().find_data (route)) == route_select_list.rows().end()) {
189                 error << _("route display list item for renamed route not found!") << endmsg;
190                 return;
191         }
192
193         route_select_list.cell ((*i)->get_row_num(), 0).set_text (route->name());
194
195         if (route == _route) {
196                 track_input_label.set_text (route->name());
197                 update_title();
198         }
199 }
200
201 void
202 RouteParams_UI::setup_redirect_boxes()
203 {
204         if (session && _route) {
205
206                 // just in case... shouldn't need this
207                 cleanup_redirect_boxes();
208                 
209                 // construct new redirect boxes
210                 pre_redirect_box = new RedirectBox(PreFader, *session, *_route, *_plugin_selector, _rr_selection);
211                 post_redirect_box = new RedirectBox(PostFader, *session, *_route, *_plugin_selector, _rr_selection);
212
213                 pre_redirect_box->set_title (pre_display_titles[0]);
214                 pre_redirect_box->set_title_shown (true);
215                 post_redirect_box->set_title (post_display_titles[0]);
216                 post_redirect_box->set_title_shown (true);
217
218                 pre_redir_hpane.add1 (*pre_redirect_box);
219                 post_redir_hpane.add1 (*post_redirect_box);
220
221                 pre_redirect_box->RedirectSelected.connect (bind (mem_fun(*this, &RouteParams_UI::redirect_selected), PreFader));
222                 pre_redirect_box->RedirectUnselected.connect (bind (mem_fun(*this, &RouteParams_UI::redirect_selected), PreFader));
223                 post_redirect_box->RedirectSelected.connect (bind (mem_fun(*this, &RouteParams_UI::redirect_selected), PostFader));
224                 post_redirect_box->RedirectUnselected.connect (bind (mem_fun(*this, &RouteParams_UI::redirect_selected), PostFader));
225                 
226         }
227         
228 }
229
230 void
231 RouteParams_UI::cleanup_redirect_boxes()
232 {
233         if (pre_redirect_box) {
234                 pre_redir_hpane.remove(*pre_redirect_box);
235                 delete pre_redirect_box;
236                 pre_redirect_box = 0;
237         }
238
239         if (post_redirect_box) {
240                 post_redir_hpane.remove(*post_redirect_box);
241                 delete post_redirect_box;
242                 post_redirect_box = 0;
243         }
244 }
245
246 void
247 RouteParams_UI::setup_io_frames()
248 {
249         cleanup_io_frames();
250         
251         // input
252         _input_iosel = new IOSelector (*session, *_route, true);
253         _input_iosel->redisplay ();
254         input_frame.add (*_input_iosel);
255         input_frame.show_all();
256         
257         // output
258         _output_iosel = new IOSelector (*session, *_route, false);
259         _output_iosel->redisplay ();
260         output_frame.add (*_output_iosel);
261         output_frame.show_all();
262 }
263
264 void
265 RouteParams_UI::cleanup_io_frames()
266 {
267         if (_input_iosel) {
268                 _input_iosel->Finished (IOSelector::Cancelled);
269                 input_frame.remove();
270                 delete _input_iosel;
271                 _input_iosel = 0;
272         }
273
274         if (_output_iosel) {
275                 _output_iosel->Finished (IOSelector::Cancelled);
276
277                 output_frame.remove();
278                 delete _output_iosel;
279                 _output_iosel = 0;
280         }
281 }
282
283 void
284 RouteParams_UI::cleanup_pre_view (bool stopupdate)
285 {
286         if (_active_pre_view) {
287                 PluginUI *   plugui = 0;
288                 
289                 if (stopupdate && (plugui = dynamic_cast<PluginUI*>(_active_pre_view)) != 0) {
290                           plugui->stop_updating (0);
291                 }
292
293                 _pre_plugin_conn.disconnect();
294                 pre_redir_hpane.remove(*_active_pre_view);
295                 delete _active_pre_view;
296                 _active_pre_view = 0;
297         }
298 }
299
300 void
301 RouteParams_UI::cleanup_post_view (bool stopupdate)
302 {
303         if (_active_post_view) {
304                 PluginUI *   plugui = 0;
305                 
306                 if (stopupdate && (plugui = dynamic_cast<PluginUI*>(_active_post_view)) != 0) {
307                           plugui->stop_updating (0);
308                 }
309                 _post_plugin_conn.disconnect();
310                 post_redir_hpane.remove(*_active_post_view);
311                 delete _active_post_view;
312                 _active_post_view = 0;
313         }
314 }
315
316
317 void
318 RouteParams_UI::route_removed (Route *route)
319 {
320         ENSURE_GUI_THREAD(bind (mem_fun(*this, &RouteParams_UI::route_removed), route));
321         /*
322         route_select_list.freeze ();
323         route_select_list.clear ();
324         session->foreach_route (this, &RouteParams_UI::add_route);
325         route_select_list.thaw ();
326         */
327         
328         CList_Helpers::RowList::iterator i;
329         
330         if ((i = route_select_list.rows().find_data (route)) == route_select_list.rows().end()) {
331                 // couldn't find route to be deleted
332                 return;
333         }
334
335         if (route == _route)
336         {
337                 cleanup_io_frames();
338                 cleanup_pre_view();
339                 cleanup_post_view();
340                 cleanup_redirect_boxes();
341                 
342                 _route = 0;
343                 _pre_redirect = 0;
344                 _post_redirect = 0;
345                 update_title();
346         }
347
348         route_select_list.rows().erase(i);
349         
350 }
351
352 void
353 RouteParams_UI::set_session (Session *sess)
354 {
355         ArdourDialog::set_session (sess);
356
357         route_select_list.freeze ();
358         route_select_list.clear ();
359
360         if (session) {
361                 session->foreach_route (this, &RouteParams_UI::add_route);
362                 session->going_away.connect (mem_fun(*this, &ArdourDialog::session_gone));
363                 session->RouteAdded.connect (mem_fun(*this, &RouteParams_UI::add_route));
364                 start_updating ();
365         } else {
366                 stop_updating ();
367         }
368
369         route_select_list.thaw ();
370
371         _plugin_selector->set_session (session);
372 }       
373
374
375 void
376 RouteParams_UI::session_gone ()
377 {
378
379         route_select_list.clear ();
380
381         cleanup_io_frames();
382         cleanup_pre_view();
383         cleanup_post_view();
384         cleanup_redirect_boxes();
385
386         _route = 0;
387         _pre_redirect = 0;
388         _post_redirect = 0;
389         update_title();
390
391         ArdourDialog::session_gone();
392
393 }
394
395 void
396 RouteParams_UI::route_selected (gint row, gint col, GdkEvent *ev)
397 {
398         Route *route;
399
400         if ((route = (Route *) route_select_list.get_row_data (row)) != 0) {
401
402                 if (_route == route) {
403                         // do nothing
404                         return;
405                 }
406                 
407                 // remove event binding from previously selected
408                 if (_route) {
409                         _route_conn.disconnect();
410                         _route_ds_conn.disconnect();
411                         cleanup_redirect_boxes();
412                         cleanup_pre_view();
413                         cleanup_post_view();
414                         cleanup_io_frames();
415                 }
416         
417                 // update the other panes with the correct info
418                 _route = route;
419                 //update_routeinfo (route);
420
421                 setup_io_frames();
422                 setup_redirect_boxes();
423                 
424                 // bind to redirects changed event for this route
425                 _route_conn = route->redirects_changed.connect (mem_fun(*this, &RouteParams_UI::redirects_changed));
426
427                 track_input_label.set_text (_route->name());
428                 
429                 update_title();
430         }
431 }
432
433 void
434 RouteParams_UI::route_unselected (gint row, gint col, GdkEvent *ev)
435 {
436         if (_route) {
437                 _route_conn.disconnect();
438
439                 // remove from view
440                 cleanup_io_frames();
441                 cleanup_pre_view();
442                 cleanup_post_view();
443                 cleanup_redirect_boxes();
444                 
445                 _route = 0;
446                 _pre_redirect = 0;
447                 _post_redirect = 0;
448                 track_input_label.set_text(_("NO TRACK"));
449                 update_title();
450         }
451 }
452
453 void
454 RouteParams_UI::redirects_changed (void *src)
455
456 {
457         ENSURE_GUI_THREAD(bind (mem_fun(*this, &RouteParams_UI::redirects_changed), src));
458         
459 //      pre_redirect_list.freeze ();
460 //      pre_redirect_list.clear ();
461 //      post_redirect_list.freeze ();
462 //      post_redirect_list.clear ();
463 //      if (_route) {
464 //              _route->foreach_redirect (this, &RouteParams_UI::add_redirect_to_display);
465 //      }
466 //      pre_redirect_list.thaw ();
467 //      post_redirect_list.thaw ();
468
469         cleanup_pre_view();
470         cleanup_post_view();
471         
472         _pre_redirect = 0;
473         _post_redirect = 0;
474         //update_title();
475 }
476
477
478
479 void
480 RouteParams_UI::show_track_menu (gint arg)
481 {
482         using namespace Menu_Helpers;
483         
484         if (track_menu == 0) {
485                 track_menu = new Menu;
486                 track_menu->set_name ("ArdourContextMenu");
487                 track_menu->items().push_back 
488                                 (MenuElem (_("Add Track/Bus"), 
489                                            mem_fun (*(ARDOUR_UI::instance()), &ARDOUR_UI::add_route)));
490         }
491         track_menu->popup (1, 0);
492 }
493
494
495
496 void
497 RouteParams_UI::redirect_selected (ARDOUR::Redirect *redirect, ARDOUR::Placement place)
498 {
499         Insert *insert;
500
501         if ((place == PreFader && _pre_redirect == redirect)
502             || (place == PostFader && _post_redirect == redirect)){
503                 return;
504         }
505         
506         if ((insert = dynamic_cast<Insert *> (redirect)) == 0) {
507
508                 Send *send;
509
510                 if ((send = dynamic_cast<Send *> (redirect)) != 0) {
511
512                         /* its a send */
513
514                         SendUI *send_ui = new SendUI (*send, *session);
515
516                         if (place == PreFader) {
517                                 cleanup_pre_view();
518                                 _pre_plugin_conn = send->GoingAway.connect (mem_fun(*this, &RouteParams_UI::redirect_going_away));
519                                 _active_pre_view = send_ui;
520                                 
521                                 pre_redir_hpane.add2 (*_active_pre_view);
522                                 pre_redir_hpane.show_all();
523                         }
524                         else {
525                                 cleanup_post_view();
526                                 _post_plugin_conn = send->GoingAway.connect (mem_fun(*this, &RouteParams_UI::redirect_going_away));
527                                 _active_post_view = send_ui;
528                                 
529                                 post_redir_hpane.add2 (*_active_post_view);
530                                 post_redir_hpane.show_all();
531                         }
532                 }
533
534         } else {
535                 /* its an insert, though we don't know what kind yet. */
536
537                 PluginInsert *plugin_insert;
538                 PortInsert *port_insert;
539                                 
540                 if ((plugin_insert = dynamic_cast<PluginInsert *> (insert)) != 0) {                             
541
542                         PluginUI *plugin_ui = new PluginUI (session->engine(), *plugin_insert, true);
543
544                         if (place == PreFader) {
545                                 cleanup_pre_view();
546                                 _pre_plugin_conn = plugin_insert->plugin().GoingAway.connect (bind (mem_fun(*this, &RouteParams_UI::plugin_going_away), PreFader));
547                                 plugin_ui->start_updating (0);
548                                 _active_pre_view = plugin_ui;
549                                 pre_redir_hpane.add2 (*_active_pre_view);
550                                 pre_redir_hpane.show_all();
551                         }
552                         else {
553                                 cleanup_post_view();
554                                 _post_plugin_conn = plugin_insert->plugin().GoingAway.connect (bind (mem_fun(*this, &RouteParams_UI::plugin_going_away), PostFader));
555                                 plugin_ui->start_updating (0);
556                                 _active_post_view = plugin_ui;
557                                 post_redir_hpane.add2 (*_active_post_view);
558                                 post_redir_hpane.show_all();
559                         }
560
561                 } else if ((port_insert = dynamic_cast<PortInsert *> (insert)) != 0) {
562
563                         PortInsertUI *portinsert_ui = new PortInsertUI (*session, *port_insert);
564                                         
565                         if (place == PreFader) {
566                                 cleanup_pre_view();
567                                 _pre_plugin_conn = port_insert->GoingAway.connect (mem_fun(*this, &RouteParams_UI::redirect_going_away));
568                                 _active_pre_view = portinsert_ui;
569                                 pre_redir_hpane.add2 (*_active_pre_view);
570                                 portinsert_ui->redisplay();
571                                 pre_redir_hpane.show_all();
572                         }
573                         else {
574                                 cleanup_post_view();
575                                 _post_plugin_conn = port_insert->GoingAway.connect (mem_fun(*this, &RouteParams_UI::redirect_going_away));
576                                 _active_post_view = portinsert_ui;
577                                 post_redir_hpane.add2 (*_active_post_view);
578                                 portinsert_ui->redisplay();
579                                 post_redir_hpane.show_all();
580                         }
581                 }
582                                 
583         }
584
585         if (place == PreFader) {
586                 _pre_redirect = redirect;
587         }
588         else {
589                 _post_redirect = redirect;
590         }
591         
592         update_title();
593                 
594 }
595
596 void
597 RouteParams_UI::redirect_unselected (ARDOUR::Redirect *redirect)
598 {
599         // not called anymore
600         
601         if (redirect == _pre_redirect) {
602                 cleanup_pre_view();
603                 _pre_redirect = 0;
604         }
605         else if (redirect == _post_redirect) {
606                 cleanup_post_view();
607                 _post_redirect = 0;
608         }
609 }
610
611
612
613 void
614 RouteParams_UI::plugin_going_away (Plugin *plugin, Placement place)
615 {
616         ENSURE_GUI_THREAD(bind (mem_fun(*this, &RouteParams_UI::plugin_going_away), plugin, place));
617         
618         // delete the current view without calling finish
619
620         if (place == PreFader) {
621                 cleanup_pre_view (false);
622                 _pre_redirect = 0;
623         }
624         else {
625                 cleanup_post_view (false);
626                 _post_redirect = 0;
627         }
628 }
629
630 void
631 RouteParams_UI::redirect_going_away (ARDOUR::Redirect *plugin)
632
633 {
634         ENSURE_GUI_THREAD(bind (mem_fun(*this, &RouteParams_UI::redirect_going_away), plugin));
635         
636         printf ("redirect going away\n");
637         // delete the current view without calling finish
638         if (plugin == _pre_redirect) {
639                 cleanup_pre_view (false);
640                 _pre_redirect = 0;
641         }
642         else if (plugin == _post_redirect) {
643                 cleanup_post_view (false);
644                 _post_redirect = 0;
645         }
646 }
647
648
649 void
650 RouteParams_UI::update_title ()
651 {
652         if (_route) {
653                 string title;
654                 title += _route->name();
655 //              title += ": ";
656
657 //              if (_redirect && (_current_view == PLUGIN_CONFIG_VIEW || _current_view == SEND_CONFIG_VIEW)) {
658 //                      title += _redirect->name();
659 //              }
660 //              else if (_current_view == INPUT_CONFIG_VIEW) {
661 //                      title += _("INPUT");
662 //              }
663 //              else if (_current_view == OUTPUT_CONFIG_VIEW) {
664 //                      title += _("OUTPUT");
665 //              }
666                 
667                 title_label.set_text(title);
668
669                 title = _("ardour: track/bus inspector: ") + title;
670                 set_title(title);
671         }
672         else {
673                 title_label.set_text(_("No Route Selected"));
674                 set_title(_("ardour: track/bus/inspector: no route selected"));
675         }       
676 }
677
678
679 void
680 RouteParams_UI::start_updating ()
681 {
682         update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect 
683                 (mem_fun(*this, &RouteParams_UI::update_views));
684 }
685
686 void
687 RouteParams_UI::stop_updating ()
688 {
689         update_connection.disconnect();
690 }
691
692 void
693 RouteParams_UI::update_views ()
694 {
695         SendUI *sui;
696         // TODO: only do it if correct tab is showing
697         
698         if ((sui = dynamic_cast<SendUI*> (_active_pre_view)) != 0) {
699                 sui->update ();
700         }
701         if ((sui = dynamic_cast<SendUI*> (_active_post_view)) != 0) {
702                 sui->update ();
703         }
704
705 }