diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 5befc7c092..58fa220b46 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -123,6 +123,8 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile) auto_loop_controllable ("transport auto loop", *this, TransportControllable::AutoLoop), play_selection_controllable ("transport play selection", *this, TransportControllable::PlaySelection), rec_controllable ("transport rec-enable", *this, TransportControllable::RecordEnable), + shuttle_controllable ("shuttle", *this, TransportControllable::ShuttleControl), + shuttle_controller_binding_proxy (shuttle_controllable), roll_button (roll_controllable), stop_button (stop_controllable), @@ -131,7 +133,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile) auto_loop_button (auto_loop_controllable), play_selection_button (play_selection_controllable), rec_button (rec_controllable), - + shuttle_units_button (_("% ")), punch_in_button (_("Punch In")), @@ -347,6 +349,63 @@ ARDOUR_UI::configure_handler (GdkEventConfigure* conf) return FALSE; } +void +ARDOUR_UI::set_transport_controllable_state (const XMLNode& node) +{ + const XMLProperty* prop; + + if ((prop = node.property ("roll")) != 0) { + roll_controllable.set_id (prop->value()); + } + if ((prop = node.property ("stop")) != 0) { + stop_controllable.set_id (prop->value()); + } + if ((prop = node.property ("goto start")) != 0) { + goto_start_controllable.set_id (prop->value()); + } + if ((prop = node.property ("goto end")) != 0) { + goto_end_controllable.set_id (prop->value()); + } + if ((prop = node.property ("auto loop")) != 0) { + auto_loop_controllable.set_id (prop->value()); + } + if ((prop = node.property ("play selection")) != 0) { + play_selection_controllable.set_id (prop->value()); + } + if ((prop = node.property ("rec")) != 0) { + rec_controllable.set_id (prop->value()); + } + if ((prop = node.property ("shuttle")) != 0) { + shuttle_controllable.set_id (prop->value()); + } +} + +XMLNode& +ARDOUR_UI::get_transport_controllable_state () +{ + XMLNode* node = new XMLNode(X_("TransportControllables")); + char buf[64]; + + roll_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("roll"), buf); + stop_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("stop"), buf); + goto_start_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("goto start"), buf); + goto_end_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("goto end"), buf); + auto_loop_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("auto loop"), buf); + play_selection_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("play selection"), buf); + rec_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("rec"), buf); + shuttle_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("shuttle"), buf); + + return *node; +} + void ARDOUR_UI::save_ardour_state () { @@ -360,6 +419,7 @@ ARDOUR_UI::save_ardour_state () XMLNode* node = new XMLNode (keyboard->get_state()); Config->add_extra_xml (*node); + Config->add_extra_xml (get_transport_controllable_state()); Config->save_state(); XMLNode enode(static_cast(editor)->get_state()); @@ -2461,6 +2521,11 @@ ARDOUR_UI::use_config () Glib::RefPtr ract = Glib::RefPtr::cast_dynamic(act); ract->set_active (); } + + XMLNode* node = Config->extra_xml (X_("TransportControllables")); + if (node) { + set_transport_controllable_state (*node); + } } void @@ -2539,6 +2604,24 @@ ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOU void ARDOUR_UI::TransportControllable::set_value (float val) { + if (type == ShuttleControl) { + + double fract; + + if (val == 63.0f) { + fract = 0.0; + } else { + if (val < 63.0f) { + fract = -((63.0f - val)/63.0f); + } else { + fract = ((val - 63.0f)/63.0f); + } + } + + ui.set_shuttle_fract (fract); + return; + } + if (val < 0.5f) { /* do nothing: these are radio-style actions */ return; @@ -2603,9 +2686,17 @@ ARDOUR_UI::TransportControllable::get_value (void) const break; case RecordEnable: break; + case ShuttleControl: + break; default: break; } return val; } + +void +ARDOUR_UI::TransportControllable::set_id (const string& str) +{ + _id = str; +} diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index 9d51232f6c..5d7421c4e3 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -365,14 +365,17 @@ class ARDOUR_UI : public Gtkmm2ext::UI GotoStart, GotoEnd, AutoLoop, - PlaySelection + PlaySelection, + ShuttleControl }; TransportControllable (std::string name, ARDOUR_UI&, ToggleType); void set_value (float); float get_value (void) const; - + + void set_id (const std::string&); + ARDOUR_UI& ui; ToggleType type; }; @@ -384,7 +387,12 @@ class ARDOUR_UI : public Gtkmm2ext::UI TransportControllable auto_loop_controllable; TransportControllable play_selection_controllable; TransportControllable rec_controllable; - + TransportControllable shuttle_controllable; + BindingProxy shuttle_controller_binding_proxy; + + void set_transport_controllable_state (const XMLNode&); + XMLNode& get_transport_controllable_state (); + BindableButton roll_button; BindableButton stop_button; BindableButton goto_start_button; @@ -424,6 +432,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI gint shuttle_box_expose (GdkEventExpose*); gint mouse_shuttle (double x, bool force); void use_shuttle_fract (bool force); + void set_shuttle_fract (double); bool shuttle_grabbed; double shuttle_fract; diff --git a/gtk2_ardour/ardour_ui2.cc b/gtk2_ardour/ardour_ui2.cc index 6fcfb32b6d..d3c3fc0690 100644 --- a/gtk2_ardour/ardour_ui2.cc +++ b/gtk2_ardour/ardour_ui2.cc @@ -649,6 +649,10 @@ ARDOUR_UI::shuttle_box_button_press (GdkEventButton* ev) return true; } + if (shuttle_controller_binding_proxy.button_press_handler (ev)) { + return true; + } + if (Keyboard::is_context_menu_event (ev)) { show_shuttle_context_menu (); return true; @@ -776,6 +780,13 @@ ARDOUR_UI::mouse_shuttle (double x, bool force) return true; } +void +ARDOUR_UI::set_shuttle_fract (double f) +{ + shuttle_fract = f; + use_shuttle_fract (false); +} + void ARDOUR_UI::use_shuttle_fract (bool force) { diff --git a/gtk2_ardour/export_dialog.cc b/gtk2_ardour/export_dialog.cc index bd4955933d..e0c11042ae 100644 --- a/gtk2_ardour/export_dialog.cc +++ b/gtk2_ardour/export_dialog.cc @@ -569,7 +569,7 @@ ExportDialog::save_state() row = *ri; track->add_property(X_("channel1"), row[exp_cols.left] ? X_("on") : X_("off")); - track->add_property(X_("channel1"), row[exp_cols.right] ? X_("on") : X_("off")); + track->add_property(X_("channel2"), row[exp_cols.right] ? X_("on") : X_("off")); tracks->add_child_nocopy(*track); } diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 3d04ff6a8b..6c4a726c0c 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -122,9 +122,9 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh visual_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::visual_click)); hide_button.signal_clicked().connect (mem_fun(*this, &RouteTimeAxisView::hide_click)); - solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press), true); + solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press), false); solo_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::solo_release)); - mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), true); + mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press), false); mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release)); if (is_track()) { diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc index 409fc04683..218eb783a9 100644 --- a/libs/ardour/audiofilesource.cc +++ b/libs/ardour/audiofilesource.cc @@ -581,5 +581,11 @@ AudioFileSource::safe_file_extension(string file) void AudioFileSource::mark_immutable () { - _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename)); + /* destructive sources stay writable, and their other flags don't + change. + */ + + if (!(_flags & Destructive)) { + _flags = Flag (_flags & ~(Writable|Removable|RemovableIfEmpty|RemoveAtDestroy|CanRename)); + } } diff --git a/libs/gtkmm2ext/gtkmm2ext/bindable_button.h b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h index 845d3fa49e..8f63c843a5 100644 --- a/libs/gtkmm2ext/gtkmm2ext/bindable_button.h +++ b/libs/gtkmm2ext/gtkmm2ext/bindable_button.h @@ -42,6 +42,7 @@ class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton bool on_button_press_event (GdkEventButton *ev) { if (!binding_proxy.button_press_handler (ev)) { + StatefulToggleButton::on_button_press_event (ev); return false; } else { return true; @@ -64,6 +65,7 @@ class BindableButton : public Gtkmm2ext::StatefulButton bool on_button_press_event (GdkEventButton *ev) { if (!binding_proxy.button_press_handler (ev)) { + StatefulButton::on_button_press_event (ev); return false; } else { return true;