summaryrefslogtreecommitdiff
path: root/gtk2_ardour
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
parent34a926fc510ebe356d8212ec3d0070124e16eb08 (diff)
Separate and consolidate Transport-Control-UI code
Diffstat (limited to 'gtk2_ardour')
-rw-r--r--gtk2_ardour/ardour_ui.cc196
-rw-r--r--gtk2_ardour/ardour_ui.h48
-rw-r--r--gtk2_ardour/ardour_ui2.cc108
-rw-r--r--gtk2_ardour/ardour_ui_dialogs.cc8
-rw-r--r--gtk2_ardour/ardour_ui_options.cc13
-rw-r--r--gtk2_ardour/transport_control.cc70
-rw-r--r--gtk2_ardour/transport_control.h65
-rw-r--r--gtk2_ardour/transport_control_ui.cc330
-rw-r--r--gtk2_ardour/transport_control_ui.h72
-rw-r--r--gtk2_ardour/wscript2
10 files changed, 552 insertions, 360 deletions
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc
index 251bd31431..2aba7ffb64 100644
--- a/gtk2_ardour/ardour_ui.cc
+++ b/gtk2_ardour/ardour_ui.cc
@@ -285,13 +285,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
, _initial_verbose_plugin_scan (false)
, first_time_engine_run (true)
, secondary_clock_spacer (0)
- , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
- , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
- , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
- , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
- , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
- , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
- , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
, auto_input_button (ArdourButton::led_default_elements)
, time_info_box (0)
, auto_return_button (ArdourButton::led_default_elements)
@@ -380,22 +373,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
UIConfiguration::instance().map_parameters (pc);
- roll_button.set_controllable (roll_controllable);
- stop_button.set_controllable (stop_controllable);
- goto_start_button.set_controllable (goto_start_controllable);
- goto_end_button.set_controllable (goto_end_controllable);
- auto_loop_button.set_controllable (auto_loop_controllable);
- play_selection_button.set_controllable (play_selection_controllable);
- rec_button.set_controllable (rec_controllable);
-
- 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");
+ transport_ctrl.setup (this);
ARDOUR::DiskWriter::Overrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
ARDOUR::DiskReader::Underrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
@@ -680,6 +658,8 @@ ARDOUR_UI::post_engine ()
throw failed_constructor ();
}
+ transport_ctrl.map_actions ();
+
/* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
XMLNode* n = Config->extra_xml (X_("UI"));
if (n) {
@@ -2620,10 +2600,6 @@ void
ARDOUR_UI::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);
layered_button.set_sensitive (false);
return;
}
@@ -2633,52 +2609,9 @@ ARDOUR_UI::map_transport_state ()
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);
- }
layered_button.set_sensitive (!_session->actively_recording ());
-
- stop_button.set_active (false);
-
} else {
-
layered_button.set_sensitive (true);
- 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);
- }
update_disk_space ();
}
}
@@ -2686,7 +2619,6 @@ ARDOUR_UI::map_transport_state ()
void
ARDOUR_UI::blink_handler (bool blink_on)
{
- transport_rec_enable_blink (blink_on);
sync_blink (blink_on);
if (!UIConfiguration::instance().get_blink_alert_indicators()) {
@@ -3130,34 +3062,6 @@ ARDOUR_UI::secondary_clock_value_changed ()
_session->request_locate (secondary_clock->current_time ());
}
}
-
-void
-ARDOUR_UI::transport_rec_enable_blink (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 ();
- }
-}
-
void
ARDOUR_UI::save_template_dialog_response (int response, SaveTemplateDialog* d)
{
@@ -5322,20 +5226,6 @@ ARDOUR_UI::update_transport_clocks (samplepos_t pos)
ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
}
-void
-ARDOUR_UI::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
ARDOUR_UI::record_state_changed ()
@@ -5402,86 +5292,6 @@ ARDOUR_UI::store_clock_modes ()
_session->set_dirty ();
}
-ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
- : Controllable (name), ui (u), type(tp)
-{
-
-}
-
-void
-ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
-{
- if (val < 0.5) {
- /* do nothing: these are radio-style actions */
- return;
- }
-
- const char *action = 0;
-
- switch (type) {
- case Roll:
- action = X_("Roll");
- break;
- case Stop:
- action = X_("Stop");
- break;
- case GotoStart:
- action = X_("GotoStart");
- break;
- case GotoEnd:
- action = X_("GotoEnd");
- break;
- case AutoLoop:
- action = X_("Loop");
- break;
- case PlaySelection:
- action = X_("PlaySelection");
- break;
- case RecordEnable:
- action = X_("Record");
- break;
- default:
- break;
- }
-
- if (action == 0) {
- return;
- }
-
- Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
-
- if (act) {
- act->activate ();
- }
-}
-
-double
-ARDOUR_UI::TransportControllable::get_value (void) const
-{
- float val = 0.0;
-
- switch (type) {
- case Roll:
- break;
- case Stop:
- break;
- case GotoStart:
- break;
- case GotoEnd:
- break;
- case AutoLoop:
- break;
- case PlaySelection:
- break;
- case RecordEnable:
- break;
- default:
- break;
- }
-
- return val;
-}
-
void
ARDOUR_UI::setup_profile ()
{
diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h
index 5413b5fde1..f714e03134 100644
--- a/gtk2_ardour/ardour_ui.h
+++ b/gtk2_ardour/ardour_ui.h
@@ -37,7 +37,6 @@
#include "pbd/xml++.h"
-#include "pbd/controllable.h"
#include <gtkmm/box.h>
#include <gtkmm/frame.h>
#include <gtkmm/label.h>
@@ -79,6 +78,8 @@
#include "enums.h"
#include "mini_timeline.h"
#include "shuttle_control.h"
+#include "transport_control.h"
+#include "transport_control_ui.h"
#include "visibility_group.h"
#include "window_manager.h"
@@ -158,7 +159,7 @@ namespace ArdourWidgets {
class Tabbable;
}
-class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
+class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr, public TransportControlProvider
{
public:
ARDOUR_UI (int *argcp, char **argvp[], const char* localedir);
@@ -372,6 +373,7 @@ protected:
void toggle_session_options_window ();
private:
+
Gtk::Window _main_window;
Gtkmm2ext::VisibilityTracker* main_window_visibility;
Gtk::VBox main_vpacker;
@@ -451,46 +453,13 @@ private:
ArdourWidgets::ArdourVSpacer* secondary_clock_spacer;
void repack_transport_hbox ();
void update_clock_visibility ();
-
- struct TransportControllable : public PBD::Controllable {
- enum ToggleType {
- Roll = 0,
- Stop,
- RecordEnable,
- GotoStart,
- GotoEnd,
- AutoLoop,
- PlaySelection,
- };
-
- TransportControllable (std::string name, ARDOUR_UI&, ToggleType);
- void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
- double get_value (void) const;
-
- ARDOUR_UI& ui;
- ToggleType type;
- };
-
- boost::shared_ptr<TransportControllable> roll_controllable;
- boost::shared_ptr<TransportControllable> stop_controllable;
- boost::shared_ptr<TransportControllable> goto_start_controllable;
- boost::shared_ptr<TransportControllable> goto_end_controllable;
- boost::shared_ptr<TransportControllable> auto_loop_controllable;
- boost::shared_ptr<TransportControllable> play_selection_controllable;
- boost::shared_ptr<TransportControllable> rec_controllable;
-
void toggle_follow_edits ();
void set_transport_controllable_state (const XMLNode&);
XMLNode& get_transport_controllable_state ();
- ArdourWidgets::ArdourButton roll_button;
- ArdourWidgets::ArdourButton stop_button;
- ArdourWidgets::ArdourButton goto_start_button;
- ArdourWidgets::ArdourButton goto_end_button;
- ArdourWidgets::ArdourButton auto_loop_button;
- ArdourWidgets::ArdourButton play_selection_button;
- ArdourWidgets::ArdourButton rec_button;
+ TransportControlUI transport_ctrl;
+
ArdourWidgets::ArdourButton punch_in_button;
ArdourWidgets::ArdourButton punch_out_button;
ArdourWidgets::ArdourButton layered_button;
@@ -518,7 +487,6 @@ private:
ArdourWidgets::ArdourButton auto_return_button;
ArdourWidgets::ArdourButton follow_edits_button;
- ArdourWidgets::ArdourButton click_button;
ArdourWidgets::ArdourButton sync_button;
ArdourWidgets::ArdourButton auditioning_alert_button;
@@ -632,7 +600,6 @@ private:
void edit_metadata ();
void import_metadata ();
- void set_loop_sensitivity ();
void set_transport_sensitivity (bool);
//stuff for ProTools-style numpad
@@ -818,8 +785,6 @@ private:
PBD::ScopedConnection halt_connection;
PBD::ScopedConnection editor_meter_connection;
- void step_edit_status_change (bool);
-
/* these are used only in response to a platform-specific "ShouldQuit" signal */
bool idle_finish ();
void queue_finish ();
@@ -829,7 +794,6 @@ private:
int ambiguous_file (std::string file, std::vector<std::string> hits);
bool click_button_clicked (GdkEventButton *);
- bool click_button_scroll (GdkEventScroll *);
bool sync_button_clicked (GdkEventButton *);
VisibilityGroup _status_bar_visibility;
diff --git a/gtk2_ardour/ardour_ui2.cc b/gtk2_ardour/ardour_ui2.cc
index ea94389b28..748cd2abd0 100644
--- a/gtk2_ardour/ardour_ui2.cc
+++ b/gtk2_ardour/ardour_ui2.cc
@@ -74,14 +74,6 @@ ARDOUR_UI::setup_tooltips ()
{
ArdourCanvas::Canvas::set_tooltip_timeout (Gtk::Settings::get_default()->property_gtk_tooltip_timeout ());
- set_tip (roll_button, _("Play from playhead"));
- set_tip (stop_button, _("Stop playback"));
- set_tip (rec_button, _("Toggle record"));
- set_tip (play_selection_button, _("Play range/selection"));
- set_tip (goto_start_button, _("Go to start of session"));
- set_tip (goto_end_button, _("Go to end of session"));
- set_tip (auto_loop_button, _("Play loop range"));
- set_tip (midi_panic_button, _("MIDI Panic\nSend note off and reset controller messages on all MIDI channels"));
set_tip (auto_return_button, _("Return to last playback start when stopped"));
set_tip (follow_edits_button, _("Playhead follows Range tool clicks, and Range selections"));
set_tip (auto_input_button, _("Track Input Monitoring automatically follows transport state"));
@@ -273,29 +265,7 @@ ARDOUR_UI::setup_transport ()
RefPtr<Action> act;
/* setup actions */
- act = ActionManager::get_action ("Transport", "ToggleClick");
- click_button.set_related_action (act);
- click_button.signal_button_press_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::click_button_clicked), false);
- click_button.signal_scroll_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::click_button_scroll), false);
-
- 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);
act = ActionManager::get_action (X_("Transport"), X_("ToggleExternalSync"));
-
sync_button.set_related_action (act);
sync_button.signal_button_press_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::sync_button_clicked), false);
@@ -381,7 +351,6 @@ ARDOUR_UI::setup_transport ()
monitor_disk_button.set_name ("monitor button");
auto_input_button.set_name ("transport option button");
- click_button.set_name ("transport button");
sync_button.set_name ("transport active option button");
/* and widget text */
@@ -418,29 +387,8 @@ ARDOUR_UI::setup_transport ()
Gtkmm2ext::UI::instance()->set_tip (monitor_in_button, _("Force all tracks to monitor Input, unless they are explicitly set to monitor Disk"));
Gtkmm2ext::UI::instance()->set_tip (monitor_disk_button, _("Force all tracks to monitor Disk playback, unless they are explicitly set to Input"));
- /* 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);
-
Glib::RefPtr<SizeGroup> punch_button_size_group = SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL);
punch_button_size_group->add_widget (punch_in_button);
punch_button_size_group->add_widget (punch_out_button);
@@ -471,23 +419,6 @@ ARDOUR_UI::setup_transport ()
transport_frame.add (*ebox);
ebox->add (transport_table);
- /* transport controls sub-group */
- click_button.set_size_request (PX_SCALE(20), PX_SCALE(20));
-
- HBox* tbox = manage (new HBox);
- tbox->set_spacing (PX_SCALE(2));
-
- tbox->pack_start (midi_panic_button, true, true, 0);
- tbox->pack_start (click_button, true, true, 0);
- tbox->pack_start (goto_start_button, true, true);
- tbox->pack_start (goto_end_button, true, true);
- tbox->pack_start (auto_loop_button, true, true);
- tbox->pack_start (play_selection_button, true, true);
-
- tbox->pack_start (roll_button, true, true);
- tbox->pack_start (stop_button, true, true);
- tbox->pack_start (rec_button, true, true, 3);
-
/* alert box sub-group */
VBox* alert_box = manage (new VBox);
alert_box->set_homogeneous (true);
@@ -505,7 +436,7 @@ ARDOUR_UI::setup_transport ()
button_height_size_group->add_widget (*secondary_clock->left_btn());
button_height_size_group->add_widget (*secondary_clock->right_btn());
- button_height_size_group->add_widget (stop_button);
+ button_height_size_group->add_widget (transport_ctrl.size_button ());
// button_height_size_group->add_widget (sync_button);
button_height_size_group->add_widget (auto_return_button);
@@ -545,7 +476,7 @@ ARDOUR_UI::setup_transport ()
int col = 0;
#define TCOL col, col + 1
- transport_table.attach (*tbox, TCOL, 0, 1 , SHRINK, SHRINK, 0, 0);
+ transport_table.attach (transport_ctrl, TCOL, 0, 1 , SHRINK, SHRINK, 0, 0);
transport_table.attach (*ssbox, TCOL, 1, 2 , FILL, SHRINK, 0, 0);
++col;
@@ -631,7 +562,6 @@ ARDOUR_UI::setup_transport ()
auditioning_alert_button.set_sensitive (false);
auditioning_alert_button.set_visual_state (Gtkmm2ext::NoVisualState);
- stop_button.set_active (true);
set_transport_sensitivity (false);
}
#undef PX_SCALE
@@ -794,17 +724,6 @@ ARDOUR_UI::error_blink (bool onoff)
break;
}
}
-
-void
-ARDOUR_UI::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
ARDOUR_UI::set_transport_sensitivity (bool yn)
{
@@ -860,29 +779,6 @@ ARDOUR_UI::click_button_clicked (GdkEventButton* ev)
}
bool
-ARDOUR_UI::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;
-}
-
-bool
ARDOUR_UI::sync_button_clicked (GdkEventButton* ev)
{
if (ev->button != 3) {
diff --git a/gtk2_ardour/ardour_ui_dialogs.cc b/gtk2_ardour/ardour_ui_dialogs.cc
index 8f1d080009..7592c34dcc 100644
--- a/gtk2_ardour/ardour_ui_dialogs.cc
+++ b/gtk2_ardour/ardour_ui_dialogs.cc
@@ -86,6 +86,8 @@ ARDOUR_UI::set_session (Session *s)
{
SessionHandlePtr::set_session (s);
+ transport_ctrl.set_session (s);
+
if (!_session) {
WM::Manager::instance().set_session (s);
/* Session option editor cannot exist across change-of-session */
@@ -158,8 +160,6 @@ ARDOUR_UI::set_session (Session *s)
ActionManager::set_sensitive (ActionManager::point_selection_sensitive_actions, false);
ActionManager::set_sensitive (ActionManager::playlist_selection_sensitive_actions, false);
- rec_button.set_sensitive (true);
-
solo_alert_button.set_active (_session->soloing());
setup_session_options ();
@@ -169,7 +169,6 @@ ARDOUR_UI::set_session (Session *s)
_session->SaveSessionRequested.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::save_session_at_its_request, this, _1), gui_context());
_session->StateSaved.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_title, this), gui_context());
_session->RecordStateChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::record_state_changed, this), gui_context());
- _session->StepEditStatusChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::step_edit_status_change, this, _1), gui_context());
_session->TransportStateChange.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::map_transport_state, this), gui_context());
_session->DirtyChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dirty_changed, this), gui_context());
@@ -179,7 +178,6 @@ ARDOUR_UI::set_session (Session *s)
_session->locations()->added.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
_session->locations()->removed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::handle_locations_change, this, _1), gui_context());
_session->config.ParameterChanged.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_parameter_changed, this, _1), gui_context ());
- _session->auto_loop_location_changed.connect (_session_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::set_loop_sensitivity, this), gui_context ());
/* Clocks are on by default after we are connected to a session, so show that here.
*/
@@ -314,8 +312,6 @@ ARDOUR_UI::unload_session (bool hide_stuff)
ActionManager::set_sensitive (ActionManager::session_sensitive_actions, false);
- rec_button.set_sensitive (false);
-
WM::Manager::instance().set_session ((ARDOUR::Session*) 0);
if (ARDOUR_UI::instance()->video_timeline) {
diff --git a/gtk2_ardour/ardour_ui_options.cc b/gtk2_ardour/ardour_ui_options.cc
index d5fac401b3..ca18c5f555 100644
--- a/gtk2_ardour/ardour_ui_options.cc
+++ b/gtk2_ardour/ardour_ui_options.cc
@@ -369,7 +369,6 @@ ARDOUR_UI::parameter_changed (std::string p)
ActionManager::get_action ("Transport", "ToggleAutoReturn")->set_sensitive (false);
ActionManager::get_action ("Transport", "ToggleFollowEdits")->set_sensitive (false);
}
- set_loop_sensitivity ();
} else if (p == "follow-edits") {
@@ -426,13 +425,6 @@ ARDOUR_UI::parameter_changed (std::string p)
}
} else if (p == "clicking") {
ActionManager::map_some_state ("Transport", "ToggleClick", &RCConfiguration::get_clicking);
- } 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 == "use-video-sync") {
ActionManager::map_some_state ("Transport", "ToggleVideoSync", sigc::mem_fun (_session->config, &SessionConfiguration::get_use_video_sync));
} else if (p == "sync-source") {
@@ -521,11 +513,6 @@ ARDOUR_UI::parameter_changed (std::string p)
/* force a redraw */
gtk_rc_reset_styles (gtk_settings_get_default());
}
- } 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_tip (click_button, string_compose (_("Enable/Disable metronome\n\nRight-click to access preferences\nMouse-wheel to modify level\nSignal Level: %1 dBFS"), tmp));
}
}
diff --git a/gtk2_ardour/transport_control.cc b/gtk2_ardour/transport_control.cc
new file mode 100644
index 0000000000..2f08b4aac0
--- /dev/null
+++ b/gtk2_ardour/transport_control.cc
@@ -0,0 +1,70 @@
+
+#include "actions.h"
+#include "transport_control.h"
+
+#include "pbd/i18n.h"
+
+using namespace Gtk;
+
+TransportControlProvider::TransportControlProvider ()
+ : roll_controllable (new TransportControllable ("transport roll", TransportControllable::Roll))
+ , stop_controllable (new TransportControllable ("transport stop", TransportControllable::Stop))
+ , goto_start_controllable (new TransportControllable ("transport goto start", TransportControllable::GotoStart))
+ , goto_end_controllable (new TransportControllable ("transport goto end", TransportControllable::GotoEnd))
+ , auto_loop_controllable (new TransportControllable ("transport auto loop", TransportControllable::AutoLoop))
+ , play_selection_controllable (new TransportControllable ("transport play selection", TransportControllable::PlaySelection))
+ , rec_controllable (new TransportControllable ("transport rec-enable", TransportControllable::RecordEnable))
+{
+}
+
+TransportControlProvider::TransportControllable::TransportControllable (std::string name, ToggleType tp)
+ : Controllable (name), type(tp)
+{
+}
+
+void
+TransportControlProvider::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
+{
+ if (val < 0.5) {
+ /* do nothing: these are radio-style actions */
+ return;
+ }
+
+ const char *action = 0;
+
+ switch (type) {
+ case Roll:
+ action = X_("Roll");
+ break;
+ case Stop:
+ action = X_("Stop");
+ break;
+ case GotoStart:
+ action = X_("GotoStart");
+ break;
+ case GotoEnd:
+ action = X_("GotoEnd");
+ break;
+ case AutoLoop:
+ action = X_("Loop");
+ break;
+ case PlaySelection:
+ action = X_("PlaySelection");
+ break;
+ case RecordEnable:
+ action = X_("Record");
+ break;
+ default:
+ break;
+ }
+
+ if (action == 0) {
+ return;
+ }
+
+ Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
+
+ if (act) {
+ act->activate ();
+ }
+}
diff --git a/gtk2_ardour/transport_control.h b/gtk2_ardour/transport_control.h
new file mode 100644
index 0000000000..8e25c15179
--- /dev/null
+++ b/gtk2_ardour/transport_control.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 1999-2017 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.
+ */
+
+#ifndef _gtkardour_transport_control_h_
+#define _gtkardour_transport_control_h_
+
+#include <gtkmm/widget.h>
+#include "pbd/controllable.h"
+
+/* This is an API implemenetd by AROUR_UI,
+ * and made available to transport-control-UIs
+ */
+class TransportControlProvider
+{
+public:
+ TransportControlProvider ();
+ virtual ~TransportControlProvider () {}
+
+ /* show metronome preferences */
+ virtual bool click_button_clicked (GdkEventButton *) = 0;
+
+ struct TransportControllable : public PBD::Controllable {
+ enum ToggleType {
+ Roll = 0,
+ Stop,
+ RecordEnable,
+ GotoStart,
+ GotoEnd,
+ AutoLoop,
+ PlaySelection,
+ };
+
+ TransportControllable (std::string name, ToggleType);
+ void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
+ double get_value (void) const { return 0; }
+
+ ToggleType type;
+ };
+
+ boost::shared_ptr<TransportControllable> roll_controllable;
+ boost::shared_ptr<TransportControllable> stop_controllable;
+ boost::shared_ptr<TransportControllable> goto_start_controllable;
+ boost::shared_ptr<TransportControllable> goto_end_controllable;
+ boost::shared_ptr<TransportControllable> auto_loop_controllable;
+ boost::shared_ptr<TransportControllable> play_selection_controllable;
+ boost::shared_ptr<TransportControllable> rec_controllable;
+};
+
+#endif
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;
+}
diff --git a/gtk2_ardour/transport_control_ui.h b/gtk2_ardour/transport_control_ui.h
new file mode 100644
index 0000000000..97476ea07f
--- /dev/null
+++ b/gtk2_ardour/transport_control_ui.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#ifndef _transport_control_ui_h_
+#define _transport_control_ui_h_
+
+#include <gtkmm/box.h>
+
+#include "pbd/signals.h"
+#include "ardour/session_handle.h"
+#include "widgets/ardour_button.h"
+
+namespace ARDOUR {
+ class Session;
+}
+
+class TransportControlProvider;
+
+class TransportControlUI : public ARDOUR::SessionHandlePtr, public Gtk::HBox
+{
+public:
+ TransportControlUI ();
+
+ void setup (TransportControlProvider*);
+ void map_actions ();
+ void set_session (ARDOUR::Session *s);
+
+ ArdourWidgets::ArdourButton& size_button () { return stop_button; }
+
+protected:
+
+ void parameter_changed (std::string p);
+
+ void blink_rec_enable (bool onoff);
+ void set_loop_sensitivity ();
+ void set_transport_sensitivity (bool);
+ void map_transport_state ();
+ void step_edit_status_change (bool yn);
+
+ bool click_button_scroll (GdkEventScroll* ev);
+
+ ArdourWidgets::ArdourButton roll_button;
+ ArdourWidgets::ArdourButton stop_button;
+ ArdourWidgets::ArdourButton goto_start_button;
+ ArdourWidgets::ArdourButton goto_end_button;
+ ArdourWidgets::ArdourButton auto_loop_button;
+ ArdourWidgets::ArdourButton play_selection_button;
+ ArdourWidgets::ArdourButton rec_button;
+ ArdourWidgets::ArdourButton midi_panic_button;
+ ArdourWidgets::ArdourButton click_button;
+
+private:
+ PBD::ScopedConnection config_connection;
+};
+
+#endif
diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript
index e883f99cb9..2555de84c4 100644
--- a/gtk2_ardour/wscript
+++ b/gtk2_ardour/wscript
@@ -259,6 +259,8 @@ gtk2_ardour_sources = [
'track_selection.cc',
'track_view_list.cc',
'transform_dialog.cc',
+ 'transport_control.cc',
+ 'transport_control_ui.cc',
'transpose_dialog.cc',
'ui_config.cc',
'utils.cc',