summaryrefslogtreecommitdiff
path: root/gtk2_ardour
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2011-11-04 17:53:21 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2011-11-04 17:53:21 +0000
commit8f078d7fd40878d08ad4d048f0606a27901c7475 (patch)
tree8eb652e8fcd0769c952b1b85e8cbd39a8d84fce3 /gtk2_ardour
parentfd2aea103790a1f49211f3bec7e9cdc246762e77 (diff)
drastic overhaul of keyboard handling in mixer window. real bindings, key events handled at window level, actions for all processor ops. still the confusing mess of old crap for the processor box context menu (it will die, i feel it)
git-svn-id: svn://localhost/ardour2/branches/3.0@10442 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour')
-rw-r--r--gtk2_ardour/mixer.bindings20
-rw-r--r--gtk2_ardour/mixer_actor.cc266
-rw-r--r--gtk2_ardour/mixer_actor.h74
-rw-r--r--gtk2_ardour/mixer_group_tabs.cc4
-rw-r--r--gtk2_ardour/mixer_strip.cc159
-rw-r--r--gtk2_ardour/mixer_strip.h14
-rw-r--r--gtk2_ardour/mixer_ui.cc165
-rw-r--r--gtk2_ardour/mixer_ui.h13
-rw-r--r--gtk2_ardour/processor_box.cc131
-rw-r--r--gtk2_ardour/processor_box.h17
-rw-r--r--gtk2_ardour/route_processor_selection.cc40
-rw-r--r--gtk2_ardour/route_processor_selection.h14
-rw-r--r--gtk2_ardour/route_ui.cc6
-rw-r--r--gtk2_ardour/route_ui.h2
-rw-r--r--gtk2_ardour/route_ui_selection.h (renamed from gtk2_ardour/route_selection.h)15
-rw-r--r--gtk2_ardour/time_axis_view.h2
-rw-r--r--gtk2_ardour/wscript1
17 files changed, 631 insertions, 312 deletions
diff --git a/gtk2_ardour/mixer.bindings b/gtk2_ardour/mixer.bindings
new file mode 100644
index 0000000000..3daeab53ca
--- /dev/null
+++ b/gtk2_ardour/mixer.bindings
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Bindings name="ardour">
+ <Press>
+ <Binding key="s" action="Mixer/solo"/>
+ <Binding key="m" action="Mixer/mute"/>
+ <Binding key="r" action="Mixer/recenable"/>
+ <Binding key="0" action="Mixer/unity-gain"/>
+ <Binding key="Up" action="Mixer/increment-gain"/>
+ <Binding key="Down" action="Mixer/decrement-gain"/>
+ <Binding key="Left" action="Mixer/scroll-left"/>
+ <Binding key="Right" action="Mixer/scroll-right"/>
+ <Binding key="Primary-x" action="Mixer/cut-processors"/>
+ <Binding key="Primary-c" action="Mixer/copy-processors"/>
+ <Binding key="Primary-v" action="Mixer/paste-processors"/>
+ <Binding key="Delete" action="Mixer/delete-processors"/>
+ <Binding key="Return" action="Mixer/toggle-processors"/>
+ <Binding key="Primary-a" action="Mixer/select-all-processors"/>
+ <Binding key="Slash" action="Mixer/ab-plugins"/>
+ </Press>
+</Bindings>
diff --git a/gtk2_ardour/mixer_actor.cc b/gtk2_ardour/mixer_actor.cc
new file mode 100644
index 0000000000..b309b9fd7f
--- /dev/null
+++ b/gtk2_ardour/mixer_actor.cc
@@ -0,0 +1,266 @@
+/*
+ Copyright (C) 2000-2004 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifdef WAF_BUILD
+#include "gtk2ardour-config.h"
+#endif
+
+#include <boost/foreach.hpp>
+
+#include "pbd/filesystem.h"
+#include "pbd/file_utils.h"
+#include "pbd/search_path.h"
+#include "pbd/error.h"
+
+#include "ardour/filesystem_paths.h"
+
+#include "actions.h"
+#include "mixer_actor.h"
+#include "mixer_strip.h"
+#include "route_ui.h"
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+using namespace Gtk;
+using namespace PBD;
+
+MixerActor::MixerActor ()
+{
+ register_actions ();
+ load_bindings ();
+}
+
+MixerActor::~MixerActor ()
+{
+}
+
+void
+MixerActor::register_actions ()
+{
+ myactions.register_action ("Mixer", "solo", _("Toggle Solo on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &MixerActor::solo_action));
+ myactions.register_action ("Mixer", "mute", _("Toggle Mute on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &MixerActor::mute_action));
+ myactions.register_action ("Mixer", "recenable", _("Toggle Rec-enable on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &MixerActor::rec_enable_action));
+ myactions.register_action ("Mixer", "increment-gain", _("Decrease Gain on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &MixerActor::step_gain_up_action));
+ myactions.register_action ("Mixer", "decrement-gain", _("Increase Gain on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &MixerActor::step_gain_down_action));
+ myactions.register_action ("Mixer", "unity-gain", _("Set Gain to 0dB on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &MixerActor::unity_gain_action));
+
+
+ myactions.register_action ("Mixer", "copy-processors", _("Copy Selected Processors"), sigc::mem_fun (*this, &MixerActor::copy_processors));
+ myactions.register_action ("Mixer", "cut-processors", _("Cut Selected Processors"), sigc::mem_fun (*this, &MixerActor::cut_processors));
+ myactions.register_action ("Mixer", "paste-processors", _("Paste Selected Processors"), sigc::mem_fun (*this, &MixerActor::paste_processors));
+ myactions.register_action ("Mixer", "delete-processors", _("Delete Selected Processors"), sigc::mem_fun (*this, &MixerActor::delete_processors));
+ myactions.register_action ("Mixer", "select-all-processors", _("Select All (visible) Processors"), sigc::mem_fun (*this, &MixerActor::select_all_processors));
+ myactions.register_action ("Mixer", "toggle-processors", _("Toggle Selected Processors"), sigc::mem_fun (*this, &MixerActor::toggle_processors));
+ myactions.register_action ("Mixer", "ab-plugins", _("Toggle Selected Plugins"), sigc::mem_fun (*this, &MixerActor::ab_plugins));
+
+
+ myactions.register_action ("Mixer", "scroll-left", _("Scroll Mixer Window to the left"), sigc::mem_fun (*this, &MixerActor::scroll_left));
+ myactions.register_action ("Mixer", "scroll-right", _("Scroll Mixer Window to the left"), sigc::mem_fun (*this, &MixerActor::scroll_right));
+}
+
+void
+MixerActor::load_bindings ()
+{
+ /* XXX move this to a better place */
+
+ bindings.set_action_map (myactions);
+
+ sys::path binding_file;
+ SearchPath spath = ardour_search_path() + user_config_directory() + system_config_search_path();
+
+ if (find_file_in_search_path (spath, "mixer.bindings", binding_file)) {
+ bindings.load (binding_file.to_string());
+ info << string_compose (_("Loaded mixer bindings from %1"), binding_file.to_string()) << endmsg;
+ } else {
+ error << string_compose (_("Could not find mixer.bindings in search path %1"), spath.to_string()) << endmsg;
+ }
+}
+
+void
+MixerActor::solo_action ()
+{
+ GdkEventButton ev;
+
+ ev.type = GDK_BUTTON_PRESS;
+ ev.button = 1;
+ ev.state = 0;
+
+ set_route_targets_for_operation ();
+
+ BOOST_FOREACH(RouteUI* r, _route_targets) {
+ r->solo_press (&ev);
+ }
+}
+
+void
+MixerActor::mute_action ()
+{
+ GdkEventButton ev;
+
+ ev.type = GDK_BUTTON_PRESS;
+ ev.button = 1;
+ ev.state = 0;
+
+ set_route_targets_for_operation ();
+
+ BOOST_FOREACH(RouteUI* r, _route_targets) {
+ r->mute_press (&ev);
+ }
+}
+
+void
+MixerActor::rec_enable_action ()
+{
+ GdkEventButton ev;
+
+ ev.type = GDK_BUTTON_PRESS;
+ ev.button = 1;
+ ev.state = 0;
+
+ set_route_targets_for_operation ();
+
+ BOOST_FOREACH(RouteUI* r, _route_targets) {
+ r->rec_enable_press (&ev);
+ }
+}
+
+void
+MixerActor::step_gain_up_action ()
+{
+ set_route_targets_for_operation ();
+
+ BOOST_FOREACH(RouteUI* r, _route_targets) {
+ MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
+ if (ms) {
+ ms->step_gain_up ();
+ }
+ }
+}
+
+void
+MixerActor::step_gain_down_action ()
+{
+ set_route_targets_for_operation ();
+
+ BOOST_FOREACH(RouteUI* r, _route_targets) {
+ MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
+ if (ms) {
+ ms->step_gain_down ();
+ }
+ }
+}
+
+void
+MixerActor::unity_gain_action ()
+{
+ set_route_targets_for_operation ();
+
+ BOOST_FOREACH(RouteUI* r, _route_targets) {
+ boost::shared_ptr<Route> rp = r->route();
+ if (rp) {
+ rp->set_gain (1.0, this);
+ }
+ }
+}
+
+void
+MixerActor::copy_processors ()
+{
+ set_route_targets_for_operation ();
+
+ BOOST_FOREACH(RouteUI* r, _route_targets) {
+ MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
+ if (ms) {
+ ms->copy_processors ();
+ }
+ }
+}
+void
+MixerActor::cut_processors ()
+{
+ set_route_targets_for_operation ();
+
+ BOOST_FOREACH(RouteUI* r, _route_targets) {
+ MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
+ if (ms) {
+ ms->cut_processors ();
+ }
+ }
+}
+void
+MixerActor::paste_processors ()
+{
+ set_route_targets_for_operation ();
+
+ BOOST_FOREACH(RouteUI* r, _route_targets) {
+ MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
+ if (ms) {
+ ms->paste_processors ();
+ }
+ }
+}
+void
+MixerActor::select_all_processors ()
+{
+ set_route_targets_for_operation ();
+
+ BOOST_FOREACH(RouteUI* r, _route_targets) {
+ MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
+ if (ms) {
+ ms->select_all_processors ();
+ }
+ }
+}
+void
+MixerActor::delete_processors ()
+{
+ set_route_targets_for_operation ();
+
+ BOOST_FOREACH(RouteUI* r, _route_targets) {
+ MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
+ if (ms) {
+ ms->delete_processors ();
+ }
+ }
+}
+void
+MixerActor::toggle_processors ()
+{
+ set_route_targets_for_operation ();
+
+ BOOST_FOREACH(RouteUI* r, _route_targets) {
+ MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
+ if (ms) {
+ ms->toggle_processors ();
+ }
+ }
+}
+void
+MixerActor::ab_plugins ()
+{
+ set_route_targets_for_operation ();
+
+ BOOST_FOREACH(RouteUI* r, _route_targets) {
+ MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
+ if (ms) {
+ ms->ab_plugins ();
+ }
+ }
+}
diff --git a/gtk2_ardour/mixer_actor.h b/gtk2_ardour/mixer_actor.h
new file mode 100644
index 0000000000..980938f8a2
--- /dev/null
+++ b/gtk2_ardour/mixer_actor.h
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2000 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __gtk2_ardour_mixer_actor_h__
+#define __gtk2_ardour_mixer_actor_h__
+
+#include <glibmm/refptr.h>
+#include <gtkmm2ext/bindings.h>
+
+#include "route_processor_selection.h"
+
+namespace Gtk {
+ class ActionGroup;
+}
+
+class MixerActor : virtual public sigc::trackable
+{
+ public:
+ MixerActor ();
+ virtual ~MixerActor ();
+
+ RouteRedirectSelection& selection() { return _selection; }
+ void register_actions ();
+
+ void load_bindings ();
+ Gtkmm2ext::Bindings bindings;
+
+ protected:
+ RouteRedirectSelection _selection;
+ RouteUISelection _route_targets;
+ Gtkmm2ext::ActionMap myactions;
+
+ virtual void set_route_targets_for_operation () = 0;
+
+ void solo_action ();
+ void mute_action ();
+ void rec_enable_action ();
+ void step_gain_up_action ();
+ void step_gain_down_action ();
+ void unity_gain_action ();
+
+ void copy_processors ();
+ void cut_processors ();
+ void paste_processors ();
+ void select_all_processors ();
+ void delete_processors ();
+ void toggle_processors ();
+ void ab_plugins ();
+
+ /* these actions don't apply to the selection, so defer to
+ a derived class.
+ */
+
+ virtual void scroll_left () {}
+ virtual void scroll_right () {}
+};
+
+#endif /* __gtk2_ardour_mixer_actor_h__ */
diff --git a/gtk2_ardour/mixer_group_tabs.cc b/gtk2_ardour/mixer_group_tabs.cc
index b74455b28d..6a6149f67f 100644
--- a/gtk2_ardour/mixer_group_tabs.cc
+++ b/gtk2_ardour/mixer_group_tabs.cc
@@ -176,7 +176,9 @@ MixerGroupTabs::order_key () const
RouteList
MixerGroupTabs::selected_routes () const
{
- return _mixer->selection().routes;
+ RouteList rl;
+ /* XXX need a foreach here */
+ return rl;
}
void
diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc
index f767396308..56c98c2024 100644
--- a/gtk2_ardour/mixer_strip.cc
+++ b/gtk2_ardour/mixer_strip.cc
@@ -1634,11 +1634,6 @@ MixerStrip::reset_strip_style ()
}
}
-RouteGroup*
-MixerStrip::route_group() const
-{
- return _route->route_group();
-}
void
MixerStrip::engine_stopped ()
@@ -1858,117 +1853,6 @@ MixerStrip::set_button_names ()
}
}
-bool
-MixerStrip::on_key_press_event (GdkEventKey* ev)
-{
- GdkEventButton fake;
- fake.type = GDK_BUTTON_PRESS;
- fake.button = 1;
- fake.state = ev->state;
-
- switch (ev->keyval) {
- case GDK_m:
- mute_press (&fake);
- return true;
- break;
-
- case GDK_s:
- solo_press (&fake);
- return true;
- break;
-
- case GDK_r:
- rec_enable_press (&fake);
- return true;
- break;
-
- case GDK_e:
- show_sends_press (&fake);
- return true;
- break;
-
- case GDK_g:
- if (ev->state & Keyboard::PrimaryModifier) {
- step_gain_down ();
- } else {
- step_gain_up ();
- }
- return true;
- break;
-
- case GDK_0:
- if (_route) {
- _route->set_gain (1.0, this);
- }
- return true;
-
- default:
- break;
- }
-
- return false;
-}
-
-
-bool
-MixerStrip::on_key_release_event (GdkEventKey* ev)
-{
- GdkEventButton fake;
- fake.type = GDK_BUTTON_RELEASE;
- fake.button = 1;
- fake.state = ev->state;
-
- switch (ev->keyval) {
- case GDK_m:
- mute_release (&fake);
- return true;
- break;
-
- case GDK_s:
- solo_release (&fake);
- return true;
- break;
-
- case GDK_r:
- rec_enable_release (&fake);
- return true;
- break;
-
- case GDK_e:
- show_sends_release (&fake);
- return true;
- break;
-
- case GDK_g:
- return true;
- break;
-
- default:
- break;
- }
-
- return false;
-}
-
-bool
-MixerStrip::on_enter_notify_event (GdkEventCrossing*)
-{
- Keyboard::magic_widget_grab_focus ();
- return false;
-}
-
-bool
-MixerStrip::on_leave_notify_event (GdkEventCrossing* ev)
-{
- switch (ev->detail) {
- case GDK_NOTIFY_INFERIOR:
- break;
- default:
- Keyboard::magic_widget_drop_focus ();
- }
-
- return false;
-}
PluginSelector*
MixerStrip::plugin_selector()
@@ -2077,3 +1961,46 @@ MixerStrip::route_active_changed ()
{
reset_strip_style ();
}
+
+void
+MixerStrip::copy_processors ()
+{
+ processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
+}
+
+void
+MixerStrip::cut_processors ()
+{
+ processor_box.processor_operation (ProcessorBox::ProcessorsCut);
+}
+
+void
+MixerStrip::paste_processors ()
+{
+ processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
+}
+
+void
+MixerStrip::select_all_processors ()
+{
+ processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
+}
+
+void
+MixerStrip::delete_processors ()
+{
+ processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
+}
+
+void
+MixerStrip::toggle_processors ()
+{
+ processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
+}
+
+void
+MixerStrip::ab_plugins ()
+{
+ processor_box.processor_operation (ProcessorBox::ProcessorsAB);
+}
+
diff --git a/gtk2_ardour/mixer_strip.h b/gtk2_ardour/mixer_strip.h
index 14d89fa1b0..6aac87850d 100644
--- a/gtk2_ardour/mixer_strip.h
+++ b/gtk2_ardour/mixer_strip.h
@@ -92,7 +92,6 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
void fast_update ();
void set_embedded (bool);
- ARDOUR::RouteGroup* route_group() const;
void set_route (boost::shared_ptr<ARDOUR::Route>);
void set_button_names ();
void show_send (boost::shared_ptr<ARDOUR::Send>);
@@ -123,6 +122,14 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
void parameter_changed (std::string);
void route_active_changed ();
+ void copy_processors ();
+ void cut_processors ();
+ void paste_processors ();
+ void select_all_processors ();
+ void delete_processors ();
+ void toggle_processors ();
+ void ab_plugins ();
+
protected:
friend class Mixer_UI;
void set_packed (bool yn);
@@ -131,11 +138,6 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
void set_selected(bool yn);
void set_stuff_from_route ();
- bool on_leave_notify_event (GdkEventCrossing* ev);
- bool on_enter_notify_event (GdkEventCrossing* ev);
- bool on_key_press_event (GdkEventKey* ev);
- bool on_key_release_event (GdkEventKey* ev);
-
private:
Mixer_UI& _mixer;
diff --git a/gtk2_ardour/mixer_ui.cc b/gtk2_ardour/mixer_ui.cc
index 2ef0956d2c..e65afb4cc7 100644
--- a/gtk2_ardour/mixer_ui.cc
+++ b/gtk2_ardour/mixer_ui.cc
@@ -68,6 +68,9 @@ using PBD::atoi;
Mixer_UI::Mixer_UI ()
: Window (Gtk::WINDOW_TOPLEVEL)
{
+ /* allow this window to become the key focus window */
+ set_flags (CAN_FOCUS);
+
_strip_width = Config->get_default_narrow_ms() ? Narrow : Wide;
track_menu = 0;
_monitor_section = 0;
@@ -80,6 +83,7 @@ Mixer_UI::Mixer_UI ()
Route::SyncOrderKeys.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::sync_order_keys, this, _1), gui_context());
+ scroller_base.set_flags (Gtk::CAN_FOCUS);
scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
scroller_base.set_name ("MixerWindow");
scroller_base.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::strip_scroller_button_release));
@@ -190,15 +194,11 @@ Mixer_UI::Mixer_UI ()
set_wmclass (X_("ardour_mixer"), PROGRAM_NAME);
- add_accel_group (ActionManager::ui_manager->get_accel_group());
-
signal_delete_event().connect (sigc::mem_fun (*this, &Mixer_UI::hide_window));
add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
- _selection.RoutesChanged.connect (sigc::mem_fun(*this, &Mixer_UI::follow_strip_selection));
-
route_group_display_button_box->show();
route_group_add_button->show();
route_group_remove_button->show();
@@ -267,6 +267,10 @@ Mixer_UI::show_window ()
ms->parameter_changed (X_("mixer-strip-visibility"));
}
}
+
+ /* force focus into main area */
+ scroller_base.grab_focus ();
+
_visible = true;
}
@@ -361,8 +365,6 @@ Mixer_UI::remove_strip (MixerStrip* strip)
ENSURE_GUI_THREAD (*this, &Mixer_UI::remove_strip, strip);
- cerr << "Mixer UI removing strip for " << strip << endl;
-
TreeModel::Children rows = track_model->children();
TreeModel::Children::iterator ri;
list<MixerStrip *>::iterator i;
@@ -429,31 +431,76 @@ Mixer_UI::sync_order_keys (string const & src)
}
}
-void
-Mixer_UI::follow_strip_selection ()
+MixerStrip*
+Mixer_UI::strip_by_route (boost::shared_ptr<Route> r)
{
for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
- (*i)->set_selected (_selection.selected ((*i)->route()));
+ if ((*i)->route() == r) {
+ return (*i);
+ }
}
+
+ return 0;
}
bool
Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip)
{
if (ev->button == 1) {
-
- /* this allows the user to click on the strip to terminate comment
- editing. XXX it needs improving so that we don't select the strip
- at the same time.
- */
-
- if (_selection.selected (strip->route())) {
- _selection.remove (strip->route());
+ if (_selection.selected (strip)) {
+ /* primary-click: toggle selection state of strip */
+ if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
+ _selection.remove (strip);
+ }
} else {
- if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
- _selection.add (strip->route());
+ if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
+ _selection.add (strip);
+ } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::RangeSelectModifier)) {
+
+ if (!_selection.selected(strip)) {
+
+ /* extend selection */
+
+ vector<MixerStrip*> tmp;
+ bool accumulate = false;
+
+ tmp.push_back (strip);
+
+ for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
+ if ((*i) == strip) {
+ /* hit clicked strip, start accumulating till we hit the first
+ selected strip
+ */
+ if (accumulate) {
+ /* done */
+ break;
+ } else {
+ accumulate = true;
+ }
+ } else if (_selection.selected (*i)) {
+ /* hit selected strip. if currently accumulating others,
+ we're done. if not accumulating others, start doing so.
+ */
+ if (accumulate) {
+ /* done */
+ break;
+ } else {
+ accumulate = true;
+ }
+ } else {
+ if (accumulate) {
+ tmp.push_back (*i);
+ }
+ }
+ }
+
+ for (vector<MixerStrip*>::iterator i = tmp.begin(); i != tmp.end(); ++i) {
+ _selection.add (*i);
+ }
+ }
+
} else {
- _selection.set (strip->route());
+ _selection.set (strip);
}
}
}
@@ -1527,29 +1574,40 @@ Mixer_UI::scroll_right ()
bool
Mixer_UI::on_key_press_event (GdkEventKey* ev)
{
- switch (ev->keyval) {
- case GDK_Left:
- scroll_left ();
- return true;
+ /* focus widget gets first shot, then bindings, otherwise
+ forward to main window
+ */
- case GDK_Right:
- scroll_right ();
+ if (gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) {
return true;
-
- default:
- break;
}
-
- return key_press_focus_accelerator_handler (*this, ev);
+
+ KeyboardKey k (ev->state, ev->keyval);
+
+ if (bindings.activate (k, Bindings::Press)) {
+ return true;
+ }
+
+ return forward_key_press (ev);
}
bool
Mixer_UI::on_key_release_event (GdkEventKey* ev)
{
- return Gtk::Window::on_key_release_event (ev);
- // return key_press_focus_accelerator_handler (*this, ev);
-}
+ if (gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) {
+ return true;
+ }
+ KeyboardKey k (ev->state, ev->keyval);
+
+ if (bindings.activate (k, Bindings::Release)) {
+ return true;
+ }
+
+ /* don't forward releases */
+
+ return true;
+}
bool
Mixer_UI::on_scroll_event (GdkEventScroll* ev)
@@ -1704,4 +1762,41 @@ Mixer_UI::update_title ()
}
}
-
+MixerStrip*
+Mixer_UI::strip_by_x (int x)
+{
+ for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
+ int x1, x2, y;
+
+ (*i)->translate_coordinates (*this, 0, 0, x1, y);
+ x2 = x1 + (*i)->get_width();
+
+ if (x >= x1 && x <= x2) {
+ return (*i);
+ }
+ }
+
+ return 0;
+}
+
+void
+Mixer_UI::set_route_targets_for_operation ()
+{
+ _route_targets.clear ();
+
+ if (!_selection.empty()) {
+ _route_targets = _selection.routes;
+ return;
+ }
+
+ /* try to get mixer strip at mouse */
+
+ int x, y;
+ get_pointer (x, y);
+
+ MixerStrip* ms = strip_by_x (x);
+
+ if (ms) {
+ _route_targets.insert (ms);
+ }
+}
diff --git a/gtk2_ardour/mixer_ui.h b/gtk2_ardour/mixer_ui.h
index 0f13d93bee..6388ed5180 100644
--- a/gtk2_ardour/mixer_ui.h
+++ b/gtk2_ardour/mixer_ui.h
@@ -39,8 +39,8 @@
#include "ardour/ardour.h"
#include "ardour/session_handle.h"
-#include "route_processor_selection.h"
#include "enums.h"
+#include "mixer_actor.h"
namespace ARDOUR {
class Route;
@@ -52,7 +52,7 @@ class PluginSelector;
class MixerGroupTabs;
class MonitorSection;
-class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public ARDOUR::SessionHandlePtr
+class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public ARDOUR::SessionHandlePtr, public MixerActor
{
public:
Mixer_UI ();
@@ -80,9 +80,11 @@ class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public AR
void toggle_auto_rebinding ();
void set_auto_rebinding(bool);
- RouteRedirectSelection& selection() { return _selection; }
MonitorSection* monitor_section() const { return _monitor_section; }
+ protected:
+ void set_route_targets_for_operation ();
+
private:
bool _visible;
@@ -128,6 +130,8 @@ class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public AR
void add_strip (ARDOUR::RouteList&);
void remove_strip (MixerStrip *);
+ MixerStrip* strip_by_route (boost::shared_ptr<ARDOUR::Route>);
+
void hide_all_strips (bool with_select);
void unselect_all_strips();
void select_all_strips ();
@@ -241,8 +245,6 @@ class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public AR
bool strip_button_release_event (GdkEventButton*, MixerStrip*);
- RouteRedirectSelection _selection;
-
Width _strip_width;
void sync_order_keys (std::string const &);
@@ -265,6 +267,7 @@ class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public AR
bool _in_group_rebuild_or_clear;
void update_title ();
+ MixerStrip* strip_by_x (int x);
friend class MixerGroupTabs;
};
diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc
index 2cdf103034..c56c18ab00 100644
--- a/gtk2_ardour/processor_box.cc
+++ b/gtk2_ardour/processor_box.cc
@@ -488,9 +488,6 @@ ProcessorBox::ProcessorBox (ARDOUR::Session* sess, boost::function<PluginSelecto
processor_display.signal_enter_notify_event().connect (sigc::mem_fun(*this, &ProcessorBox::enter_notify), false);
processor_display.signal_leave_notify_event().connect (sigc::mem_fun(*this, &ProcessorBox::leave_notify), false);
- processor_display.signal_key_press_event().connect (sigc::mem_fun(*this, &ProcessorBox::processor_key_press_event));
- processor_display.signal_key_release_event().connect (sigc::mem_fun(*this, &ProcessorBox::processor_key_release_event));
-
processor_display.ButtonPress.connect (sigc::mem_fun (*this, &ProcessorBox::processor_button_press_event));
processor_display.ButtonRelease.connect (sigc::mem_fun (*this, &ProcessorBox::processor_button_release_event));
@@ -696,49 +693,19 @@ bool
ProcessorBox::enter_notify (GdkEventCrossing*)
{
_current_processor_box = this;
- Keyboard::magic_widget_grab_focus ();
- processor_display.grab_focus ();
-
return false;
}
bool
ProcessorBox::leave_notify (GdkEventCrossing* ev)
{
- switch (ev->detail) {
- case GDK_NOTIFY_INFERIOR:
- break;
- default:
- Keyboard::magic_widget_drop_focus ();
- }
-
return false;
}
-bool
-ProcessorBox::processor_key_press_event (GdkEventKey *ev)
-{
- switch (ev->keyval) {
- case GDK_a:
- case GDK_c:
- case GDK_x:
- case GDK_v:
- case GDK_Up:
- case GDK_Down:
- case GDK_Delete:
- case GDK_BackSpace:
- case GDK_Return:
- case GDK_slash:
- /* do real stuff on key release */
- return true;
- }
-
- return false;
-}
-
-bool
-ProcessorBox::processor_key_release_event (GdkEventKey *ev)
+void
+ProcessorBox::processor_operation (ProcessorOperation op)
{
+
bool ret = false;
ProcSelection targets;
@@ -756,57 +723,32 @@ ProcessorBox::processor_key_release_event (GdkEventKey *ev)
}
}
-
- switch (ev->keyval) {
- case GDK_a:
- if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
- processor_display.select_all ();
- ret = true;
- }
+ switch (op) {
+ case ProcessorsSelectAll:
+ processor_display.select_all ();
break;
- case GDK_c:
- if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
- copy_processors (targets);
- ret = true;
- }
+ case ProcessorsCopy:
+ copy_processors (targets);
break;
- case GDK_x:
- if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
- cut_processors (targets);
- ret = true;
- }
+ case ProcessorsCut:
+ cut_processors (targets);
break;
- case GDK_v:
- if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
- if (targets.empty()) {
- paste_processors ();
- } else {
- paste_processors (targets.front());
- }
- ret = true;
+ case ProcessorsPaste:
+ if (targets.empty()) {
+ paste_processors ();
+ } else {
+ paste_processors (targets.front());
}
break;
- case GDK_Up:
- processors_down ();
- ret = true;
- break;
-
- case GDK_Down:
- processors_up ();
- ret = true;
- break;
-
- case GDK_Delete:
- case GDK_BackSpace:
+ case ProcessorsDelete:
delete_processors (targets);
- ret = true;
break;
- case GDK_Return:
+ case ProcessorsToggleActive:
for (ProcSelection::iterator i = targets.begin(); i != targets.end(); ++i) {
if ((*i)->active()) {
(*i)->deactivate ();
@@ -817,16 +759,13 @@ ProcessorBox::processor_key_release_event (GdkEventKey *ev)
ret = true;
break;
- case GDK_slash:
+ case ProcessorsAB:
ab_plugins ();
- ret = true;
break;
default:
break;
}
-
- return ret;
}
bool
@@ -1403,14 +1342,6 @@ ProcessorBox::can_cut () const
}
void
-ProcessorBox::cut_processors ()
-{
- ProcSelection to_be_removed;
-
- get_selected_processors (to_be_removed);
-}
-
-void
ProcessorBox::cut_processors (const ProcSelection& to_be_removed)
{
if (to_be_removed.empty()) {
@@ -1452,14 +1383,6 @@ ProcessorBox::cut_processors (const ProcSelection& to_be_removed)
}
void
-ProcessorBox::copy_processors ()
-{
- ProcSelection to_be_copied;
- get_selected_processors (to_be_copied);
- copy_processors (to_be_copied);
-}
-
-void
ProcessorBox::copy_processors (const ProcSelection& to_be_copied)
{
if (to_be_copied.empty()) {
@@ -1494,14 +1417,6 @@ ProcessorBox::processors_down ()
void
-ProcessorBox::delete_processors ()
-{
- ProcSelection to_be_deleted;
- get_selected_processors (to_be_deleted);
- delete_processors (to_be_deleted);
-}
-
-void
ProcessorBox::delete_processors (const ProcSelection& targets)
{
if (targets.empty()) {
@@ -2136,7 +2051,7 @@ ProcessorBox::rb_cut ()
return;
}
- _current_processor_box->cut_processors ();
+ _current_processor_box->processor_operation (ProcessorsCut);
}
void
@@ -2146,7 +2061,7 @@ ProcessorBox::rb_delete ()
return;
}
- _current_processor_box->delete_processors ();
+ _current_processor_box->processor_operation (ProcessorsDelete);
}
void
@@ -2155,7 +2070,7 @@ ProcessorBox::rb_copy ()
if (_current_processor_box == 0) {
return;
}
- _current_processor_box->copy_processors ();
+ _current_processor_box->processor_operation (ProcessorsCopy);
}
void
@@ -2165,7 +2080,7 @@ ProcessorBox::rb_paste ()
return;
}
- _current_processor_box->paste_processors ();
+ _current_processor_box->processor_operation (ProcessorsPaste);
}
void
@@ -2184,7 +2099,7 @@ ProcessorBox::rb_select_all ()
return;
}
- _current_processor_box->select_all_processors ();
+ _current_processor_box->processor_operation (ProcessorsSelectAll);
}
void
diff --git a/gtk2_ardour/processor_box.h b/gtk2_ardour/processor_box.h
index 5d80e8a360..f6b4fc2fe6 100644
--- a/gtk2_ardour/processor_box.h
+++ b/gtk2_ardour/processor_box.h
@@ -194,6 +194,16 @@ private:
class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARDOUR::SessionHandlePtr
{
public:
+ enum ProcessorOperation {
+ ProcessorsCut,
+ ProcessorsCopy,
+ ProcessorsPaste,
+ ProcessorsDelete,
+ ProcessorsSelectAll,
+ ProcessorsToggleActive,
+ ProcessorsAB,
+ };
+
ProcessorBox (ARDOUR::Session*, boost::function<PluginSelector*()> get_plugin_selector,
RouteRedirectSelection&, MixerStrip* parent, bool owner_is_mixer = false);
~ProcessorBox ();
@@ -203,6 +213,8 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
void update();
+ void processor_operation (ProcessorOperation);
+
void select_all_processors ();
void deselect_all_processors ();
void select_all_plugins ();
@@ -279,8 +291,6 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
bool enter_notify (GdkEventCrossing *ev);
bool leave_notify (GdkEventCrossing *ev);
- bool processor_key_press_event (GdkEventKey *);
- bool processor_key_release_event (GdkEventKey *);
bool processor_button_press_event (GdkEventButton *, ProcessorEntry *);
bool processor_button_release_event (GdkEventButton *, ProcessorEntry *);
void redisplay_processors ();
@@ -300,11 +310,8 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
typedef std::vector<boost::shared_ptr<ARDOUR::Processor> > ProcSelection;
void cut_processors (const ProcSelection&);
- void cut_processors ();
void copy_processors (const ProcSelection&);
- void copy_processors ();
void delete_processors (const ProcSelection&);
- void delete_processors ();
void paste_processors ();
void paste_processors (boost::shared_ptr<ARDOUR::Processor> before);
void processors_up ();
diff --git a/gtk2_ardour/route_processor_selection.cc b/gtk2_ardour/route_processor_selection.cc
index b3a6620f6b..9022119729 100644
--- a/gtk2_ardour/route_processor_selection.cc
+++ b/gtk2_ardour/route_processor_selection.cc
@@ -25,8 +25,10 @@
#include "ardour/processor.h"
#include "ardour/route.h"
-#include "route_processor_selection.h"
#include "gui_thread.h"
+#include "mixer_strip.h"
+#include "route_processor_selection.h"
+#include "route_ui.h"
#include "i18n.h"
@@ -68,6 +70,9 @@ RouteRedirectSelection::clear_processors ()
void
RouteRedirectSelection::clear_routes ()
{
+ for (RouteUISelection::iterator i = routes.begin(); i != routes.end(); ++i) {
+ (*i)->set_selected (false);
+ }
routes.clear ();
drop_connections ();
RoutesChanged ();
@@ -90,48 +95,45 @@ RouteRedirectSelection::set (XMLNode* node)
}
void
-RouteRedirectSelection::add (boost::shared_ptr<Route> r)
+RouteRedirectSelection::add (RouteUI* r)
{
if (find (routes.begin(), routes.end(), r) == routes.end()) {
- routes.push_back (r);
- r->DropReferences.connect (*this, MISSING_INVALIDATOR, boost::bind (&RouteRedirectSelection::removed, this, boost::weak_ptr<Route>(r)), gui_context());
- RoutesChanged();
- }
-}
+ if (routes.insert (r).second) {
+ r->set_selected (true);
-void
-RouteRedirectSelection::removed (boost::weak_ptr<Route> wr)
-{
- boost::shared_ptr<Route> r (wr.lock());
+ MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
+
+ if (ms) {
+ ms->CatchDeletion.connect (*this, invalidator (*this), ui_bind (&RouteRedirectSelection::remove, this, _1), gui_context());
+ }
- if (!r) {
- return;
+ RoutesChanged();
+ }
}
-
- remove (r);
}
void
-RouteRedirectSelection::remove (boost::shared_ptr<Route> r)
+RouteRedirectSelection::remove (RouteUI* r)
{
ENSURE_GUI_THREAD (*this, &RouteRedirectSelection::remove, r);
- list<boost::shared_ptr<Route> >::iterator i;
+ RouteUISelection::iterator i;
if ((i = find (routes.begin(), routes.end(), r)) != routes.end()) {
routes.erase (i);
+ (*i)->set_selected (false);
RoutesChanged ();
}
}
void
-RouteRedirectSelection::set (boost::shared_ptr<Route> r)
+RouteRedirectSelection::set (RouteUI* r)
{
clear_routes ();
add (r);
}
bool
-RouteRedirectSelection::selected (boost::shared_ptr<Route> r)
+RouteRedirectSelection::selected (RouteUI* r)
{
return find (routes.begin(), routes.end(), r) != routes.end();
}
diff --git a/gtk2_ardour/route_processor_selection.h b/gtk2_ardour/route_processor_selection.h
index df43019e91..08616f0d50 100644
--- a/gtk2_ardour/route_processor_selection.h
+++ b/gtk2_ardour/route_processor_selection.h
@@ -24,13 +24,13 @@
#include "pbd/signals.h"
#include "processor_selection.h"
-#include "route_selection.h"
+#include "route_ui_selection.h"
class RouteRedirectSelection : public PBD::ScopedConnectionList, public sigc::trackable
{
public:
ProcessorSelection processors;
- RouteSelection routes;
+ RouteUISelection routes;
RouteRedirectSelection() {}
@@ -45,17 +45,17 @@ class RouteRedirectSelection : public PBD::ScopedConnectionList, public sigc::tr
void set (XMLNode* node);
void add (XMLNode* node);
- void set (boost::shared_ptr<ARDOUR::Route>);
- void add (boost::shared_ptr<ARDOUR::Route>);
- void remove (boost::shared_ptr<ARDOUR::Route>);
+ void set (RouteUI*);
+ void add (RouteUI*);
+ void remove (RouteUI*);
void clear_processors ();
void clear_routes ();
- bool selected (boost::shared_ptr<ARDOUR::Route>);
+ bool selected (RouteUI*);
private:
- void removed (boost::weak_ptr<ARDOUR::Route>);
+ void removed (RouteUI*);
};
diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc
index 007c35a5b6..552439b993 100644
--- a/gtk2_ardour/route_ui.cc
+++ b/gtk2_ardour/route_ui.cc
@@ -1936,3 +1936,9 @@ RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
send_blink_connection.disconnect ();
}
}
+
+RouteGroup*
+RouteUI::route_group() const
+{
+ return _route->route_group();
+}
diff --git a/gtk2_ardour/route_ui.h b/gtk2_ardour/route_ui.h
index 8c774522ee..1240de8716 100644
--- a/gtk2_ardour/route_ui.h
+++ b/gtk2_ardour/route_ui.h
@@ -36,6 +36,7 @@
#include "ardour/track.h"
#include "axis_view.h"
+#include "selectable.h"
namespace ARDOUR {
class AudioTrack;
@@ -70,6 +71,7 @@ class RouteUI : public virtual AxisView
bool has_audio_outputs () const;
boost::shared_ptr<ARDOUR::Route> route() const { return _route; }
+ ARDOUR::RouteGroup* route_group() const;
boost::shared_ptr<ARDOUR::Track> track() const;
boost::shared_ptr<ARDOUR::AudioTrack> audio_track() const;
diff --git a/gtk2_ardour/route_selection.h b/gtk2_ardour/route_ui_selection.h
index c11feabc13..b26e1c6f54 100644
--- a/gtk2_ardour/route_selection.h
+++ b/gtk2_ardour/route_ui_selection.h
@@ -17,17 +17,14 @@
*/
-#ifndef __ardour_gtk_route_selection_h__
-#define __ardour_gtk_route_selection_h__
+#ifndef __ardour_gtk_route_ui_selection_h__
+#define __ardour_gtk_route_ui_selection_h__
-#include <boost/shared_ptr.hpp>
-#include <list>
+#include <set>
-namespace ARDOUR {
- class Route;
-}
+class RouteUI;
-struct RouteSelection : std::list<boost::shared_ptr<ARDOUR::Route> > {};
+struct RouteUISelection : std::set<RouteUI*> {};
-#endif /* __ardour_gtk_route_selection_h__ */
+#endif /* __ardour_gtk_route_ui_selection_h__ */
diff --git a/gtk2_ardour/time_axis_view.h b/gtk2_ardour/time_axis_view.h
index 59315df055..790274c626 100644
--- a/gtk2_ardour/time_axis_view.h
+++ b/gtk2_ardour/time_axis_view.h
@@ -131,7 +131,7 @@ class TimeAxisView : public virtual AxisView
/** @return true if hidden, otherwise false */
bool hidden () const { return _hidden; }
- virtual void set_selected (bool);
+ void set_selected (bool);
/**
* potential handler for entered events
diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript
index a0a1861001..1aabd02f1a 100644
--- a/gtk2_ardour/wscript
+++ b/gtk2_ardour/wscript
@@ -148,6 +148,7 @@ gtk2_ardour_sources = [
'midi_tracer.cc',
'missing_file_dialog.cc',
'missing_plugin_dialog.cc',
+ 'mixer_actor.cc',
'mixer_group_tabs.cc',
'mixer_strip.cc',
'mixer_ui.cc',