create and manage a new config parameter that defines where LTC originates (still...
[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/rc_configuration.h"
30 #include "ardour/session.h"
31
32 #ifdef HAVE_LIBLO
33 #include "ardour/osc.h"
34 #endif
35
36 #include "audio_clock.h"
37 #include "ardour_ui.h"
38 #include "actions.h"
39 #include "gui_thread.h"
40 #include "public_editor.h"
41 #include "main_clock.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::update_tearoff_visibility();
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 (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
282         if (act) {
283                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
284                 if (tact->get_active()) {
285                         maximise_editing_space ();
286                 } else {
287                         restore_editing_space ();
288                 }
289         }
290 }
291
292 void
293 ARDOUR_UI::setup_session_options ()
294 {
295         _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
296         boost::function<void (std::string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
297         _session->config.map_parameters (pc);
298 }
299
300 void
301 ARDOUR_UI::parameter_changed (std::string p)
302 {
303         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::parameter_changed, p)
304
305         if (p == "external-sync") {
306
307                 ActionManager::map_some_state ("Transport", "ToggleExternalSync", sigc::mem_fun (_session->config, &SessionConfiguration::get_external_sync));
308
309                 if (!_session->config.get_external_sync()) {
310                         sync_button.set_text (_("Internal"));
311                         ActionManager::get_action ("Transport", "ToggleAutoPlay")->set_sensitive (true);
312                         ActionManager::get_action ("Transport", "ToggleAutoReturn")->set_sensitive (true);
313                 } else {
314                         sync_button.set_text (sync_source_to_string (Config->get_sync_source(), true));
315                         /* XXX need to make auto-play is off as well as insensitive */
316                         ActionManager::get_action ("Transport", "ToggleAutoPlay")->set_sensitive (false);
317                         ActionManager::get_action ("Transport", "ToggleAutoReturn")->set_sensitive (false);
318                 }
319
320         } else if (p == "always-play-range") {
321
322                 ActionManager::map_some_state ("Transport", "AlwaysPlayRange", &RCConfiguration::get_always_play_range);
323
324         } else if (p == "send-mtc") {
325
326                 ActionManager::map_some_state ("options", "SendMTC", &RCConfiguration::get_send_mtc);
327
328         } else if (p == "send-mmc") {
329
330                 ActionManager::map_some_state ("options", "SendMMC", &RCConfiguration::get_send_mmc);
331
332         } else if (p == "use-osc") {
333
334 #ifdef HAVE_LIBLO
335                 if (Config->get_use_osc()) {
336                         osc->start ();
337                 } else {
338                         osc->stop ();
339                 }
340 #endif
341
342         } else if (p == "keep-tearoffs") {
343                 ActionManager::map_some_state ("Common", "KeepTearoffs", &RCConfiguration::get_keep_tearoffs);
344         } else if (p == "mmc-control") {
345                 ActionManager::map_some_state ("options", "UseMMC", &RCConfiguration::get_mmc_control);
346         } else if (p == "midi-feedback") {
347                 ActionManager::map_some_state ("options", "SendMIDIfeedback", &RCConfiguration::get_midi_feedback);
348         } else if (p == "auto-play") {
349                 ActionManager::map_some_state ("Transport", "ToggleAutoPlay", sigc::mem_fun (_session->config, &SessionConfiguration::get_auto_play));
350         } else if (p == "auto-return") {
351                 ActionManager::map_some_state ("Transport", "ToggleAutoReturn", sigc::mem_fun (_session->config, &SessionConfiguration::get_auto_return));
352         } else if (p == "auto-input") {
353                 ActionManager::map_some_state ("Transport", "ToggleAutoInput", sigc::mem_fun (_session->config, &SessionConfiguration::get_auto_input));
354         } else if (p == "punch-out") {
355                 ActionManager::map_some_state ("Transport", "TogglePunchOut", sigc::mem_fun (_session->config, &SessionConfiguration::get_punch_out));
356                 if (!_session->config.get_punch_out()) {
357                         unset_dual_punch ();
358                 }
359         } else if (p == "punch-in") {
360                 ActionManager::map_some_state ("Transport", "TogglePunchIn", sigc::mem_fun (_session->config, &SessionConfiguration::get_punch_in));
361                 if (!_session->config.get_punch_in()) {
362                         unset_dual_punch ();
363                 }
364         } else if (p == "clicking") {
365                 ActionManager::map_some_state ("Transport", "ToggleClick", &RCConfiguration::get_clicking);
366         } else if (p == "use-video-sync") {
367                 ActionManager::map_some_state ("Transport",  "ToggleVideoSync", sigc::mem_fun (_session->config, &SessionConfiguration::get_use_video_sync));
368         } else if (p == "video-pullup" || p == "timecode-format") {
369
370                 synchronize_sync_source_and_video_pullup ();
371                 reset_main_clocks ();
372
373         } else if (p == "sync-source") {
374
375                 synchronize_sync_source_and_video_pullup ();
376
377         } else if (p == "show-track-meters") {
378                 editor->toggle_meter_updating();
379         } else if (p == "primary-clock-delta-edit-cursor") {
380                 if (Config->get_primary_clock_delta_edit_cursor()) {
381                         primary_clock->set_is_duration (true);
382                         primary_clock->set_editable (false);
383                         primary_clock->set_widget_name ("transport delta");
384                 } else {
385                         primary_clock->set_is_duration (false);
386                         primary_clock->set_editable (true);
387                         primary_clock->set_widget_name ("transport");
388                 }
389         } else if (p == "secondary-clock-delta-edit-cursor") {
390                 if (Config->get_secondary_clock_delta_edit_cursor()) {
391                         secondary_clock->set_is_duration (true);
392                         secondary_clock->set_editable (false);
393                         secondary_clock->set_widget_name ("secondary delta");
394                 } else {
395                         secondary_clock->set_is_duration (false);
396                         secondary_clock->set_editable (true);
397                         secondary_clock->set_widget_name ("secondary");
398                 }
399         }
400 }
401
402 void
403 ARDOUR_UI::session_parameter_changed (std::string p)
404 {
405         if (p == "native-file-data-format" || p == "native-file-header-format") {
406                 update_format ();
407         }
408 }
409
410 void
411 ARDOUR_UI::reset_main_clocks ()
412 {
413         ENSURE_GUI_THREAD (*this, &ARDOUR_UI::reset_main_clocks)
414
415         if (_session) {
416                 primary_clock->set (_session->audible_frame(), true);
417                 secondary_clock->set (_session->audible_frame(), true);
418         } else {
419                 primary_clock->set (0, true);
420                 secondary_clock->set (0, true);
421         }
422 }
423
424 void
425 ARDOUR_UI::synchronize_sync_source_and_video_pullup ()
426 {
427         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Transport"), X_("ToggleExternalSync"));
428
429         if (!act) {
430                 return;
431         }
432
433         if (!_session) {
434                 goto just_label;
435         }
436
437         if (_session->config.get_video_pullup() == 0.0f) {
438                 /* with no video pull up/down, any sync source is OK */
439                 act->set_sensitive (true);
440         } else {
441                 /* can't sync to JACK if video pullup != 0.0 */
442                 if (Config->get_sync_source() == JACK) {
443                         act->set_sensitive (false);
444                 } else {
445                         act->set_sensitive (true);
446                 }
447         }
448
449         /* XXX should really be able to set the video pull up
450            action to insensitive/sensitive, but there is no action.
451            FIXME
452         */
453
454   just_label:
455         if (act->get_sensitive ()) {
456                 set_tip (sync_button, _("Enable/Disable external positional sync"));
457         } else {
458                 set_tip (sync_button, _("Sync to JACK is not possible: video pull up/down is set"));
459         }
460
461 }
462