diff --git a/gtk2_ardour/trigger_page.cc b/gtk2_ardour/trigger_page.cc index b94eaddb98..1288e21902 100644 --- a/gtk2_ardour/trigger_page.cc +++ b/gtk2_ardour/trigger_page.cc @@ -69,6 +69,7 @@ TriggerPage::TriggerPage () , _cue_box (16, 16 * default_triggers_per_box) , _master_widget (16, 16) , _master (_master_widget.root ()) + , _selection (*this, *this) { load_bindings (); register_actions (); @@ -266,6 +267,7 @@ TriggerPage::set_session (Session* s) _trigger_route_list.set_session (s); if (!_session) { + _selection.clear (); return; } @@ -297,6 +299,10 @@ TriggerPage::set_session (Session* s) update_title (); start_updating (); selection_changed (); + + PBD::PropertyChange sc; + sc.add (Properties::selected); + _selection.presentation_info_changed (sc); } void @@ -312,6 +318,7 @@ TriggerPage::session_going_away () delete (*i); } #endif + _selection.clear (); _strips.clear (); SessionHandlePtr::session_going_away (); @@ -432,6 +439,7 @@ TriggerPage::add_routes (RouteList& rl) (*r)->presentation_info ().PropertyChanged.connect (*this, invalidator (*this), boost::bind (&TriggerPage::stripable_property_changed, this, _1, boost::weak_ptr (*r)), gui_context ()); (*r)->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&TriggerPage::stripable_property_changed, this, _1, boost::weak_ptr (*r)), gui_context ()); + ts->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &TriggerPage::strip_button_release_event), ts)); } redisplay_track_list (); } @@ -464,6 +472,7 @@ void TriggerPage::redisplay_track_list () { _strips.sort (TriggerStripSorter ()); + PresentationInfo::ChangeSuspender cs; for (list::iterator i = _strips.begin (); i != _strips.end (); ++i) { TriggerStrip* strip = *i; @@ -472,6 +481,12 @@ TriggerPage::redisplay_track_list () bool hidden = s->presentation_info ().hidden (); + if (s->is_selected ()) { + _selection.add (*i); + } else { + _selection.remove (*i); + } + if (!(s)->presentation_info ().trigger_track ()) { hidden = true; } @@ -492,6 +507,25 @@ TriggerPage::redisplay_track_list () } } +AxisView* +TriggerPage::axis_view_by_stripable (boost::shared_ptr s) const +{ + for (list::const_iterator i = _strips.begin (); i != _strips.end (); ++i) { + TriggerStrip* strip = *i; + if (s == strip->stripable ()) { + return strip; + } + } + return 0; +} + +AxisView* +TriggerPage::axis_view_by_control (boost::shared_ptr c) const +{ + return 0; +} + + void TriggerPage::rec_state_clicked () { @@ -512,6 +546,9 @@ TriggerPage::parameter_changed (string const& p) void TriggerPage::pi_property_changed (PBD::PropertyChange const& what_changed) { + if (what_changed.contains (Properties::selected)) { + _selection.presentation_info_changed (what_changed); + } if (what_changed.contains (ARDOUR::Properties::order)) { redisplay_track_list (); } @@ -535,6 +572,87 @@ TriggerPage::stripable_property_changed (PBD::PropertyChange const& what_changed } } +bool +TriggerPage::strip_button_release_event (GdkEventButton *ev, TriggerStrip *strip) +{ + if (ev->button != 1) { + return false; + } + + if (_selection.selected (strip)) { + /* primary-click: toggle selection state of strip */ + if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { + _selection.remove (strip, true); + } else if (_selection.axes.size() > 1) { + /* de-select others */ + _selection.set (strip); + } + PublicEditor& pe = PublicEditor::instance(); + TimeAxisView* tav = pe.time_axis_view_from_stripable (strip->stripable()); + if (tav) { + pe.set_selected_mixer_strip (*tav); + } + } else { + if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { + _selection.add (strip, true); + } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::RangeSelectModifier)) { + + /* extend selection */ + + vector tmp; + bool accumulate = false; + bool found_another = false; + + _strips.sort (TriggerStripSorter ()); + + for (list::iterator i = _strips.begin (); i != _strips.end (); ++i) { + TriggerStrip* ts = *i; + + if (ts == strip) { + /* hit clicked strip, start accumulating till we hit the first + selected strip + */ + if (accumulate) { + /* done */ + break; + } else { + accumulate = true; + } + } else if (_selection.selected (ts)) { + /* hit selected strip. if currently accumulating others, + we're done. if not accumulating others, start doing so. + */ + found_another = true; + if (accumulate) { + /* done */ + break; + } else { + accumulate = true; + } + } else { + if (accumulate) { + tmp.push_back (ts); + } + } + } + + tmp.push_back (strip); + + if (found_another) { + PresentationInfo::ChangeSuspender cs; + for (vector::iterator i = tmp.begin(); i != tmp.end(); ++i) { + _selection.add (*i, true); + } + } else { + _selection.set (strip); //user wants to start a range selection, but there aren't any others selected yet + } + } else { + _selection.set (strip); + } + } + return true; +} + bool TriggerPage::no_strip_button_event (GdkEventButton* ev) { diff --git a/gtk2_ardour/trigger_page.h b/gtk2_ardour/trigger_page.h index de21b421e0..8be4904dbc 100644 --- a/gtk2_ardour/trigger_page.h +++ b/gtk2_ardour/trigger_page.h @@ -38,6 +38,7 @@ #include "midi_region_operations_box.h" #include "midi_region_properties_box.h" #include "midi_trigger_properties_box.h" +#include "route_processor_selection.h" #include "slot_properties_box.h" #include "trigger_clip_picker.h" #include "trigger_region_list.h" @@ -47,7 +48,7 @@ class TriggerStrip; -class TriggerPage : public ArdourWidgets::Tabbable, public ARDOUR::SessionHandlePtr, public PBD::ScopedConnectionList +class TriggerPage : public ArdourWidgets::Tabbable, public ARDOUR::SessionHandlePtr, public PBD::ScopedConnectionList, public AxisViewProvider { public: TriggerPage (); @@ -60,6 +61,8 @@ public: Gtk::Window* use_own_window (bool and_fill_it); + RouteProcessorSelection& selection() { return _selection; } + private: void load_bindings (); void register_actions (); @@ -80,6 +83,7 @@ private: void add_sidebar_page (std::string const&, Gtk::Widget&); + bool strip_button_release_event (GdkEventButton*, TriggerStrip*); bool no_strip_button_event (GdkEventButton*); bool no_strip_drag_motion (Glib::RefPtr const&, int, int, guint); void no_strip_drag_data_received (Glib::RefPtr const&, int, int, Gtk::SelectionData const&, guint, guint); @@ -87,6 +91,9 @@ private: bool idle_drop_paths (std::vector); void drop_paths_part_two (std::vector); + AxisView* axis_view_by_stripable (boost::shared_ptr) const; + AxisView* axis_view_by_control (boost::shared_ptr) const; + void selection_changed (); PBD::ScopedConnectionList editor_connections; @@ -130,6 +137,7 @@ private: MidiClipEditorBox _midi_trim_box; #endif + RouteProcessorSelection _selection; std::list _strips; sigc::connection _fast_screen_update_connection; }; diff --git a/gtk2_ardour/trigger_strip.cc b/gtk2_ardour/trigger_strip.cc index 90c003adbc..a0174ff615 100644 --- a/gtk2_ardour/trigger_strip.cc +++ b/gtk2_ardour/trigger_strip.cc @@ -403,6 +403,22 @@ TriggerStrip::route_property_changed (const PropertyChange& what_changed) } } +void +TriggerStrip::set_selected (bool yn) +{ + AxisView::set_selected (yn); + + if (selected()) { + global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT); + global_frame.set_name ("MixerStripSelectedFrame"); + } else { + global_frame.set_shadow_type (Gtk::SHADOW_IN); + global_frame.set_name ("MixerStripFrame"); + } + + global_frame.queue_draw (); +} + void TriggerStrip::route_color_changed () { diff --git a/gtk2_ardour/trigger_strip.h b/gtk2_ardour/trigger_strip.h index b2c95fc817..d6e6dfd2d7 100644 --- a/gtk2_ardour/trigger_strip.h +++ b/gtk2_ardour/trigger_strip.h @@ -59,6 +59,7 @@ public: } void set_session (ARDOUR::Session* s); + void set_selected (bool yn); void fast_update (); diff --git a/gtk2_ardour/triggerbox_ui.cc b/gtk2_ardour/triggerbox_ui.cc index 3a946ee689..7bc4ca4110 100644 --- a/gtk2_ardour/triggerbox_ui.cc +++ b/gtk2_ardour/triggerbox_ui.cc @@ -563,7 +563,6 @@ TriggerEntry::name_button_event (GdkEvent* ev) } break; case GDK_BUTTON_PRESS: - PublicEditor::instance ().get_selection ().set (this); break; case GDK_2BUTTON_PRESS: #if SELECTION_PROPERTIES_BOX_TODO @@ -573,8 +572,12 @@ TriggerEntry::name_button_event (GdkEvent* ev) case GDK_BUTTON_RELEASE: switch (ev->button.button) { case 3: + PublicEditor::instance ().get_selection ().set (this); context_menu (); return true; + case 1: + PublicEditor::instance ().get_selection ().set (this); + return true; default: break; }