summaryrefslogtreecommitdiff
path: root/gtk2_ardour/transport_control_ui.cc
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2017-12-22 20:20:59 +0100
committerRobin Gareus <robin@gareus.org>2017-12-22 22:15:50 +0100
commitaab787f686e6287a06ba94ed8c87b524c4690f0f (patch)
tree274012a8cb968252dff99735c2be9b4e59a7a988 /gtk2_ardour/transport_control_ui.cc
parent34a926fc510ebe356d8212ec3d0070124e16eb08 (diff)
Separate and consolidate Transport-Control-UI code
Diffstat (limited to 'gtk2_ardour/transport_control_ui.cc')
-rw-r--r--gtk2_ardour/transport_control_ui.cc330
1 files changed, 330 insertions, 0 deletions
diff --git a/gtk2_ardour/transport_control_ui.cc b/gtk2_ardour/transport_control_ui.cc
new file mode 100644
index 0000000000..8102f51b43
--- /dev/null
+++ b/gtk2_ardour/transport_control_ui.cc
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2017 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2013 Paul Davis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <gtkmm/sizegroup.h>
+
+#include "ardour/dB.h"
+#include "widgets/tooltips.h"
+#include "gtkmm2ext/gui_thread.h"
+
+#include "actions.h"
+#include "ardour_ui.h"
+#include "timers.h"
+#include "transport_control_ui.h"
+
+#include "pbd/i18n.h"
+
+using namespace Glib;
+using namespace Gtk;
+using namespace ARDOUR;
+using namespace ArdourWidgets;
+
+TransportControlUI::TransportControlUI ()
+{
+ Config->ParameterChanged.connect (config_connection, MISSING_INVALIDATOR, boost::bind (&TransportControlUI::parameter_changed, this, _1), gui_context());
+}
+
+void
+TransportControlUI::map_actions ()
+{
+ /* setup actions */
+ RefPtr<Action> act;
+
+ act = ActionManager::get_action (X_("Transport"), X_("ToggleClick"));
+ click_button.set_related_action (act);
+ act = ActionManager::get_action (X_("Transport"), X_("Stop"));
+ stop_button.set_related_action (act);
+ act = ActionManager::get_action (X_("Transport"), X_("Roll"));
+ roll_button.set_related_action (act);
+ act = ActionManager::get_action (X_("Transport"), X_("Record"));
+ rec_button.set_related_action (act);
+ act = ActionManager::get_action (X_("Transport"), X_("GotoStart"));
+ goto_start_button.set_related_action (act);
+ act = ActionManager::get_action (X_("Transport"), X_("GotoEnd"));
+ goto_end_button.set_related_action (act);
+ act = ActionManager::get_action (X_("Transport"), X_("Loop"));
+ auto_loop_button.set_related_action (act);
+ act = ActionManager::get_action (X_("Transport"), X_("PlaySelection"));
+ play_selection_button.set_related_action (act);
+
+ act = ActionManager::get_action (X_("MIDI"), X_("panic"));
+ midi_panic_button.set_related_action (act);
+
+ /* tooltips depend on actions */
+ set_tooltip (roll_button, _("Play from playhead"));
+ set_tooltip (stop_button, _("Stop playback"));
+ set_tooltip (rec_button, _("Toggle record"));
+ set_tooltip (play_selection_button, _("Play range/selection"));
+ set_tooltip (goto_start_button, _("Go to start of session"));
+ set_tooltip (goto_end_button, _("Go to end of session"));
+ set_tooltip (auto_loop_button, _("Play loop range"));
+ set_tooltip (midi_panic_button, _("MIDI Panic\nSend note off and reset controller messages on all MIDI channels"));
+
+ /* set click_button tooltip */
+ parameter_changed ("click-gain");
+}
+
+void
+TransportControlUI::setup (TransportControlProvider* ui)
+{
+ click_button.signal_button_press_event().connect (sigc::mem_fun (*ui, &TransportControlProvider::click_button_clicked), false);
+ click_button.signal_scroll_event().connect (sigc::mem_fun (*this, &TransportControlUI::click_button_scroll), false);
+
+ /* setup icons */
+
+ click_button.set_icon (ArdourIcon::TransportMetronom);
+ goto_start_button.set_icon (ArdourIcon::TransportStart);
+ goto_end_button.set_icon (ArdourIcon::TransportEnd);
+ roll_button.set_icon (ArdourIcon::TransportPlay);
+ stop_button.set_icon (ArdourIcon::TransportStop);
+ play_selection_button.set_icon (ArdourIcon::TransportRange);
+ auto_loop_button.set_icon (ArdourIcon::TransportLoop);
+ rec_button.set_icon (ArdourIcon::RecButton);
+ midi_panic_button.set_icon (ArdourIcon::TransportPanic);
+
+ /* transport control size-group */
+
+ Glib::RefPtr<SizeGroup> transport_button_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
+ transport_button_size_group->add_widget (goto_start_button);
+ transport_button_size_group->add_widget (goto_end_button);
+ transport_button_size_group->add_widget (auto_loop_button);
+ transport_button_size_group->add_widget (rec_button);
+ transport_button_size_group->add_widget (play_selection_button);
+ transport_button_size_group->add_widget (roll_button);
+ transport_button_size_group->add_widget (stop_button);
+
+ transport_button_size_group->add_widget (midi_panic_button);
+ transport_button_size_group->add_widget (click_button);
+
+#define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
+
+ click_button.set_size_request (PX_SCALE(20), PX_SCALE(20));
+ set_spacing (PX_SCALE(2));
+
+#undef PX_SCALE
+
+ pack_start (midi_panic_button, true, true, 0);
+ pack_start (click_button, true, true, 0);
+ pack_start (goto_start_button, true, true);
+ pack_start (goto_end_button, true, true);
+ pack_start (auto_loop_button, true, true);
+ pack_start (play_selection_button, true, true);
+ pack_start (roll_button, true, true);
+ pack_start (stop_button, true, true);
+ pack_start (rec_button, true, true, 3);
+
+ roll_button.set_name ("transport button");
+ stop_button.set_name ("transport button");
+ goto_start_button.set_name ("transport button");
+ goto_end_button.set_name ("transport button");
+ auto_loop_button.set_name ("transport button");
+ play_selection_button.set_name ("transport button");
+ rec_button.set_name ("transport recenable button");
+ midi_panic_button.set_name ("transport button"); // XXX ???
+ click_button.set_name ("transport button");
+
+ roll_button.set_controllable (ui->roll_controllable);
+ stop_button.set_controllable (ui->stop_controllable);
+ goto_start_button.set_controllable (ui->goto_start_controllable);
+ goto_end_button.set_controllable (ui->goto_end_controllable);
+ auto_loop_button.set_controllable (ui->auto_loop_controllable);
+ play_selection_button.set_controllable (ui->play_selection_controllable);
+ rec_button.set_controllable (ui->rec_controllable);
+
+ stop_button.set_active (true);
+
+ Timers::blink_connect (sigc::mem_fun (*this, &TransportControlUI::blink_rec_enable));
+}
+
+void
+TransportControlUI::set_session (ARDOUR::Session *s)
+{
+ SessionHandlePtr::set_session (s);
+ set_loop_sensitivity ();
+
+ if (!_session) {
+ rec_button.set_sensitive (false);
+ return;
+ }
+
+ _session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&TransportControlUI::parameter_changed, this, _1), gui_context());
+ _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&TransportControlUI::step_edit_status_change, this, _1), gui_context());
+ _session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&TransportControlUI::map_transport_state, this), gui_context());
+ _session->auto_loop_location_changed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&TransportControlUI::set_loop_sensitivity, this), gui_context ());
+
+ rec_button.set_sensitive (true);
+}
+
+void
+TransportControlUI::parameter_changed (std::string p)
+{
+ if (p == "external-sync") {
+ set_loop_sensitivity ();
+ } else if (p == "click-record-only") {
+ // TODO set a flag, blink or gray-out metronome button while rolling, only
+ if (Config->get_click_record_only()) {
+ click_button.set_name ("generic button"); // XXX
+ } else {
+ click_button.set_name ("transport button");
+ }
+ } else if (p == "click-gain") {
+ float gain_db = accurate_coefficient_to_dB (Config->get_click_gain());
+ char tmp[32];
+ snprintf(tmp, 31, "%+.1f", gain_db);
+ set_tooltip (click_button, string_compose (_("Enable/Disable metronome\n\nRight-click to access preferences\nMouse-wheel to modify level\nSignal Level: %1 dBFS"), tmp));
+ }
+}
+
+void
+TransportControlUI::map_transport_state ()
+{
+ if (!_session) {
+ auto_loop_button.unset_active_state ();
+ play_selection_button.unset_active_state ();
+ roll_button.unset_active_state ();
+ stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
+ return;
+ }
+
+ float sp = _session->transport_speed();
+
+ if (sp != 0.0f) {
+
+ /* we're rolling */
+
+ if (_session->get_play_range()) {
+
+ play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
+ roll_button.unset_active_state ();
+ auto_loop_button.unset_active_state ();
+
+ } else if (_session->get_play_loop ()) {
+
+ auto_loop_button.set_active (true);
+ play_selection_button.set_active (false);
+
+ if (Config->get_loop_is_mode()) {
+ roll_button.set_active (true);
+ } else {
+ roll_button.set_active (false);
+ }
+
+ } else {
+
+ roll_button.set_active (true);
+ play_selection_button.set_active (false);
+ auto_loop_button.set_active (false);
+
+ }
+
+ if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
+ /* light up both roll and play-selection if they are joined */
+ roll_button.set_active (true);
+ play_selection_button.set_active (true);
+ }
+
+ stop_button.set_active (false);
+
+ } else {
+
+ stop_button.set_active (true);
+ roll_button.set_active (false);
+ play_selection_button.set_active (false);
+ if (Config->get_loop_is_mode ()) {
+ auto_loop_button.set_active (_session->get_play_loop());
+ } else {
+ auto_loop_button.set_active (false);
+ }
+ }
+}
+
+void
+TransportControlUI::step_edit_status_change (bool yn)
+{
+ // XXX should really store pre-step edit status of things
+ // we make insensitive
+
+ if (yn) {
+ rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
+ rec_button.set_sensitive (false);
+ } else {
+ rec_button.unset_active_state ();;
+ rec_button.set_sensitive (true);
+ }
+}
+
+void
+TransportControlUI::set_loop_sensitivity ()
+{
+ if (!_session || _session->config.get_external_sync()) {
+ auto_loop_button.set_sensitive (false);
+ } else {
+ auto_loop_button.set_sensitive (_session && _session->locations()->auto_loop_location());
+ }
+}
+
+void
+TransportControlUI::blink_rec_enable (bool onoff)
+{
+ if (_session == 0) {
+ return;
+ }
+
+ if (_session->step_editing()) {
+ return;
+ }
+
+ Session::RecordState const r = _session->record_status ();
+ bool const h = _session->have_rec_enabled_track ();
+
+ if (r == Session::Enabled || (r == Session::Recording && !h)) {
+ if (onoff) {
+ rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
+ } else {
+ rec_button.set_active_state (Gtkmm2ext::Off);
+ }
+ } else if (r == Session::Recording && h) {
+ rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
+ } else {
+ rec_button.unset_active_state ();
+ }
+}
+
+bool
+TransportControlUI::click_button_scroll (GdkEventScroll* ev)
+{
+ gain_t gain = Config->get_click_gain();
+ float gain_db = accurate_coefficient_to_dB (gain);
+
+ switch (ev->direction) {
+ case GDK_SCROLL_UP:
+ case GDK_SCROLL_LEFT:
+ gain_db += 1;
+ break;
+ case GDK_SCROLL_DOWN:
+ case GDK_SCROLL_RIGHT:
+ gain_db -= 1;
+ break;
+ }
+ gain_db = std::max (-60.f, gain_db);
+ gain = dB_to_coefficient (gain_db);
+ gain = std::min (gain, Config->get_max_gain());
+ Config->set_click_gain (gain);
+ return true;
+}