change appearance of panner data popup slightly (fixed width font so it doesn't bounc...
[ardour.git] / gtk2_ardour / ardour_ui_options.cc
1 /*
2     Copyright (C) 2005 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 #include "pbd/convert.h"
25 #include "pbd/stacktrace.h"
26
27 #include <gtkmm2ext/utils.h>
28
29 #include "ardour/configuration.h"
30 #include "ardour/session.h"
31 #include "ardour/audioengine.h"
32 #include "ardour/rc_configuration.h"
33
34 #ifdef HAVE_LIBLO
35 #include "ardour/osc.h"
36 #endif
37
38 #include "ardour_ui.h"
39 #include "actions.h"
40 #include "gui_thread.h"
41 #include "public_editor.h"
42
43 #include "i18n.h"
44
45 using namespace Gtk;
46 using namespace Gtkmm2ext;
47 using namespace ARDOUR;
48 using namespace PBD;
49
50 void
51 ARDOUR_UI::toggle_keep_tearoffs ()
52 {
53         ActionManager::toggle_config_state ("Common", "KeepTearoffs", &RCConfiguration::set_keep_tearoffs, &RCConfiguration::get_keep_tearoffs);
54  
55         ARDOUR_UI::toggle_editing_space ();
56 }
57
58 void
59 ARDOUR_UI::toggle_external_sync()
60 {
61         if (_session) {
62                 if (_session->config.get_video_pullup() != 0.0f) {
63                         if (_session->config.get_sync_source() == JACK) {
64                                 MessageDialog msg (
65                                         _("It is not possible to use JACK as the the sync source\n\
66 when the pull up/down setting is non-zero."));
67                                 msg.run ();
68                                 return;
69                         }
70                 }
71                                                                    
72                 ActionManager::toggle_config_state_foo ("Transport", "ToggleExternalSync", sigc::mem_fun (_session->config, &SessionConfiguration::set_external_sync), sigc::mem_fun (_session->config, &SessionConfiguration::get_external_sync));
73         }
74 }
75
76 void
77 ARDOUR_UI::toggle_time_master ()
78 {
79         ActionManager::toggle_config_state_foo ("Transport", "ToggleTimeMaster", sigc::mem_fun (_session->config, &SessionConfiguration::set_jack_time_master), sigc::mem_fun (_session->config, &SessionConfiguration::get_jack_time_master));
80 }
81
82 void
83 ARDOUR_UI::toggle_send_mtc ()
84 {
85         ActionManager::toggle_config_state ("options", "SendMTC", &RCConfiguration::set_send_mtc, &RCConfiguration::get_send_mtc);
86 }
87
88 void
89 ARDOUR_UI::toggle_send_mmc ()
90 {
91         ActionManager::toggle_config_state ("options", "SendMMC", &RCConfiguration::set_send_mmc, &RCConfiguration::get_send_mmc);
92 }
93
94 void
95 ARDOUR_UI::toggle_send_midi_clock ()
96 {
97         ActionManager::toggle_config_state ("options", "SendMidiClock", &RCConfiguration::set_send_midi_clock, &RCConfiguration::get_send_midi_clock);
98 }
99
100 void
101 ARDOUR_UI::toggle_use_mmc ()
102 {
103         ActionManager::toggle_config_state ("options", "UseMMC", &RCConfiguration::set_mmc_control, &RCConfiguration::get_mmc_control);
104 }
105
106 void
107 ARDOUR_UI::toggle_send_midi_feedback ()
108 {
109         ActionManager::toggle_config_state ("options", "SendMIDIfeedback", &RCConfiguration::set_midi_feedback, &RCConfiguration::get_midi_feedback);
110 }
111
112 void
113 ARDOUR_UI::toggle_auto_input ()
114 {
115         ActionManager::toggle_config_state_foo ("Transport", "ToggleAutoInput", sigc::mem_fun (_session->config, &SessionConfiguration::set_auto_input), sigc::mem_fun (_session->config, &SessionConfiguration::get_auto_input));
116 }
117
118 void
119 ARDOUR_UI::toggle_auto_play ()
120 {
121         ActionManager::toggle_config_state_foo ("Transport", "ToggleAutoPlay", sigc::mem_fun (_session->config, &SessionConfiguration::set_auto_play), sigc::mem_fun (_session->config, &SessionConfiguration::get_auto_play));
122 }
123
124 void
125 ARDOUR_UI::toggle_auto_return ()
126 {
127         ActionManager::toggle_config_state_foo ("Transport", "ToggleAutoReturn", sigc::mem_fun (_session->config, &SessionConfiguration::set_auto_return), sigc::mem_fun (_session->config, &SessionConfiguration::get_auto_return));
128 }
129
130 void
131 ARDOUR_UI::toggle_click ()
132 {
133         ActionManager::toggle_config_state ("Transport", "ToggleClick", &RCConfiguration::set_clicking, &RCConfiguration::get_clicking);
134 }
135
136 void
137 ARDOUR_UI::unset_dual_punch ()
138 {
139         Glib::RefPtr<Action> action = ActionManager::get_action ("Transport", "TogglePunch");
140
141         if (action) {
142                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action);
143                 if (tact) {
144                         ignore_dual_punch = true;
145                         tact->set_active (false);
146                         ignore_dual_punch = false;
147                 }
148         }
149 }
150
151 void
152 ARDOUR_UI::toggle_punch ()
153 {
154         if (ignore_dual_punch) {
155                 return;
156         }
157
158         Glib::RefPtr<Action> action = ActionManager::get_action ("Transport", "TogglePunch");
159
160         if (action) {
161
162                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action);
163
164                 if (!tact) {
165                         return;
166                 }
167
168                 /* drive the other two actions from this one */
169
170                 Glib::RefPtr<Action> in_action = ActionManager::get_action ("Transport", "TogglePunchIn");
171                 Glib::RefPtr<Action> out_action = ActionManager::get_action ("Transport", "TogglePunchOut");
172
173                 if (in_action && out_action) {
174                         Glib::RefPtr<ToggleAction> tiact = Glib::RefPtr<ToggleAction>::cast_dynamic(in_action);
175                         Glib::RefPtr<ToggleAction> toact = Glib::RefPtr<ToggleAction>::cast_dynamic(out_action);
176                         tiact->set_active (tact->get_active());
177                         toact->set_active (tact->get_active());
178                 }
179         }
180 }
181
182 void
183 ARDOUR_UI::toggle_punch_in ()
184 {
185         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Transport"), X_("TogglePunchIn"));
186         if (!act) {
187                 return;
188         }
189
190         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
191         if (!tact) {
192                 return;
193         }
194
195         if (tact->get_active() != _session->config.get_punch_in()) {
196                 _session->config.set_punch_in (tact->get_active ());
197         }
198
199         if (tact->get_active()) {
200                 /* if punch-in is turned on, make sure the loop/punch ruler is visible, and stop it being hidden,
201                    to avoid confusing the user */
202                 show_loop_punch_ruler_and_disallow_hide ();
203         }
204
205         reenable_hide_loop_punch_ruler_if_appropriate ();
206 }
207
208 void
209 ARDOUR_UI::toggle_punch_out ()
210 {
211         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Transport"), X_("TogglePunchOut"));
212         if (!act) {
213                 return;
214         }
215
216         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
217         if (!tact) {
218                 return;
219         }
220
221         if (tact->get_active() != _session->config.get_punch_out()) {
222                 _session->config.set_punch_out (tact->get_active ());
223         }
224
225         if (tact->get_active()) {
226                 /* if punch-out is turned on, make sure the loop/punch ruler is visible, and stop it being hidden,
227                    to avoid confusing the user */
228                 show_loop_punch_ruler_and_disallow_hide ();
229         }
230
231         reenable_hide_loop_punch_ruler_if_appropriate ();
232 }
233
234 void
235 ARDOUR_UI::show_loop_punch_ruler_and_disallow_hide ()
236 {
237         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Rulers"), "toggle-loop-punch-ruler");
238         if (!act) {
239                 return;
240         }
241
242         act->set_sensitive (false);
243         
244         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
245         if (!tact) {
246                 return;
247         }
248         
249         if (!tact->get_active()) {
250                 tact->set_active ();
251         }
252 }
253
254 /* This is a bit of a silly name for a method */
255 void
256 ARDOUR_UI::reenable_hide_loop_punch_ruler_if_appropriate ()
257 {
258         if (!_session->config.get_punch_in() && !_session->config.get_punch_out()) {
259                 /* if punch in/out are now both off, reallow hiding of the loop/punch ruler */
260                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Rulers"), "toggle-loop-punch-ruler");
261                 if (act) {
262                         act->set_sensitive (true);
263                 }
264         }
265 }
266
267 void
268 ARDOUR_UI::toggle_video_sync()
269 {
270         Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", "ToggleVideoSync");
271         if (act) {
272                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
273                 _session->config.set_use_video_sync (tact->get_active());
274         }
275 }
276
277 void
278 ARDOUR_UI::toggle_editing_space()
279 {
280         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMaximalEditor");
281         if (act) {
282                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
283                 if (tact->get_active()) {
284                         maximise_editing_space ();
285                 } else {
286                         restore_editing_space ();
287                 }
288         }
289 }
290
291 void
292 ARDOUR_UI::setup_session_options ()
293 {
294         _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, ui_bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
295         boost::function<void (std::string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
296         _session->config.map_parameters (pc);
297 }
298
299 #if 0
300 void
301 ARDOUR_UI::handle_sync_change ()
302 {
303         if (!_session) {
304                 return;
305         }
306         if (!_session->config.get_external_sync()) {
307                 sync_button.set_label (_("Internal"));
308                 ActionManager::get_action ("Transport", "ToggleAutoPlay")->set_sensitive (true);
309                 ActionManager::get_action ("Transport", "ToggleAutoReturn")->set_sensitive (true);
310         } else {
311                 sync_button.set_label (_("External"));
312                 /* XXX need to make auto-play is off as well as insensitive */
313                 ActionManager::get_action ("Transport", "ToggleAutoPlay")->set_sensitive (false);
314                 ActionManager::get_action ("Transport", "ToggleAutoReturn")->set_sensitive (false);
315         }
316
317 }
318 #endif
319
320 void
321 ARDOUR_UI::parameter_changed (std::string p)
322 {
323         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::parameter_changed, p)
324
325         if (p == "external-sync") {
326
327                 ActionManager::map_some_state ("Transport", "ToggleExternalSync", sigc::mem_fun (_session->config, &SessionConfiguration::get_external_sync));
328
329                 if (!_session->config.get_external_sync()) {
330                         sync_button.set_label (_("Internal"));
331                         ActionManager::get_action ("Transport", "ToggleAutoPlay")->set_sensitive (true);
332                         ActionManager::get_action ("Transport", "ToggleAutoReturn")->set_sensitive (true);
333                 } else {
334                         sync_button.set_label (sync_source_to_string (_session->config.get_sync_source(), true));
335                         /* XXX need to make auto-play is off as well as insensitive */
336                         ActionManager::get_action ("Transport", "ToggleAutoPlay")->set_sensitive (false);
337                         ActionManager::get_action ("Transport", "ToggleAutoReturn")->set_sensitive (false);
338                 }
339         
340         } else if (p == "send-mtc") {
341
342                 ActionManager::map_some_state ("options", "SendMTC", &RCConfiguration::get_send_mtc);
343
344         } else if (p == "send-mmc") {
345
346                 ActionManager::map_some_state ("options", "SendMMC", &RCConfiguration::get_send_mmc);
347
348         } else if (p == "use-osc") {
349
350 #ifdef HAVE_LIBLO
351                 if (Config->get_use_osc()) {
352                         osc->start ();
353                 } else {
354                         osc->stop ();
355                 }
356 #endif
357
358         } else if (p == "keep-tearoffs") {
359                 ActionManager::map_some_state ("Common", "KeepTearoffs", &RCConfiguration::get_keep_tearoffs);
360         } else if (p == "mmc-control") {
361                 ActionManager::map_some_state ("options", "UseMMC", &RCConfiguration::get_mmc_control);
362         } else if (p == "midi-feedback") {
363                 ActionManager::map_some_state ("options", "SendMIDIfeedback", &RCConfiguration::get_midi_feedback);
364         } else if (p == "auto-play") {
365                 ActionManager::map_some_state ("Transport", "ToggleAutoPlay", sigc::mem_fun (_session->config, &SessionConfiguration::get_auto_play));
366         } else if (p == "auto-return") {
367                 ActionManager::map_some_state ("Transport", "ToggleAutoReturn", sigc::mem_fun (_session->config, &SessionConfiguration::get_auto_return));
368         } else if (p == "auto-input") {
369                 ActionManager::map_some_state ("Transport", "ToggleAutoInput", sigc::mem_fun (_session->config, &SessionConfiguration::get_auto_input));
370         } else if (p == "punch-out") {
371                 ActionManager::map_some_state ("Transport", "TogglePunchOut", sigc::mem_fun (_session->config, &SessionConfiguration::get_punch_out));
372                 if (!_session->config.get_punch_out()) {
373                         unset_dual_punch ();
374                 }
375         } else if (p == "punch-in") {
376                 ActionManager::map_some_state ("Transport", "TogglePunchIn", sigc::mem_fun (_session->config, &SessionConfiguration::get_punch_in));
377                 if (!_session->config.get_punch_in()) {
378                         unset_dual_punch ();
379                 }
380         } else if (p == "clicking") {
381                 ActionManager::map_some_state ("Transport", "ToggleClick", &RCConfiguration::get_clicking);
382         } else if (p == "jack-time-master") {
383                 ActionManager::map_some_state ("Transport",  "ToggleTimeMaster", sigc::mem_fun (_session->config, &SessionConfiguration::get_jack_time_master));
384         } else if (p == "use-video-sync") {
385                 ActionManager::map_some_state ("Transport",  "ToggleVideoSync", sigc::mem_fun (_session->config, &SessionConfiguration::get_use_video_sync));
386         } else if (p == "shuttle-behaviour") {
387
388                 switch (Config->get_shuttle_behaviour ()) {
389                 case Sprung:
390                         shuttle_style_button.set_active_text (_("sprung"));
391                         shuttle_fract = 0.0;
392                         shuttle_box.queue_draw ();
393                         if (_session) {
394                                 if (_session->transport_rolling()) {
395                                         shuttle_fract = SHUTTLE_FRACT_SPEED1;
396                                         _session->request_transport_speed (1.0);
397                                 }
398                         }
399                         break;
400                 case Wheel:
401                         shuttle_style_button.set_active_text (_("wheel"));
402                         break;
403                 }
404
405         } else if (p == "shuttle-units") {
406
407                 switch (Config->get_shuttle_units()) {
408                 case Percentage:
409                         shuttle_units_button.set_label("% ");
410                         break;
411                 case Semitones:
412                         shuttle_units_button.set_label(_("ST"));
413                         break;
414                 }
415         } else if (p == "video-pullup" || p == "timecode-format") {
416
417                 synchronize_sync_source_and_video_pullup ();
418                 reset_main_clocks ();
419
420         } else if (p == "sync-source") {
421
422                 synchronize_sync_source_and_video_pullup ();
423
424         } else if (p == "show-track-meters") {
425                 editor->toggle_meter_updating();
426         } else if (p == "primary-clock-delta-edit-cursor") {
427                 primary_clock.set_is_duration (Config->get_primary_clock_delta_edit_cursor());
428         } else if (p == "secondary-clock-delta-edit-cursor") {
429                 secondary_clock.set_is_duration (Config->get_secondary_clock_delta_edit_cursor());
430         }
431 }
432
433 void
434 ARDOUR_UI::reset_main_clocks ()
435 {
436         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::reset_main_clocks)
437
438         if (_session) {
439                 primary_clock.set (_session->audible_frame(), true);
440                 secondary_clock.set (_session->audible_frame(), true);
441         } else {
442                 primary_clock.set (0, true);
443                 secondary_clock.set (0, true);
444         }
445 }
446
447 void
448 ARDOUR_UI::synchronize_sync_source_and_video_pullup ()
449 {
450         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Transport"), X_("ToggleExternalSync"));
451
452         if (!act) {
453                 return;
454         }
455
456         if (!_session) {
457                 goto just_label;
458         }
459
460         if (_session->config.get_video_pullup() == 0.0f) {
461                 /* with no video pull up/down, any sync source is OK */
462                 act->set_sensitive (true);
463         } else {
464                 /* can't sync to JACK if video pullup != 0.0 */
465                 if (_session->config.get_sync_source() == JACK) {
466                         act->set_sensitive (false);
467                 } else {
468                         act->set_sensitive (true);
469                 }
470         }
471
472         /* XXX should really be able to set the video pull up
473            action to insensitive/sensitive, but there is no action.
474            FIXME
475         */
476
477   just_label:
478         if (act->get_sensitive ()) {
479                 set_tip (sync_button, _("Enable/Disable external positional sync"));
480         } else {
481                 set_tip (sync_button, _("Sync to JACK is not possible: video pull up/down is set"));
482         }
483
484 }
485