From f2251dd1c2fdbe14ed6ff2f09e411affd0a55591 Mon Sep 17 00:00:00 2001 From: VKamyshniy Date: Mon, 28 Jul 2014 11:06:02 +0300 Subject: [PATCH] [Summary] Progressing UI --- gtk2_ardour/editor.cc | 5 +- gtk2_ardour/editor.h | 3 +- gtk2_ardour/editor_mixer.cc | 1 + gtk2_ardour/icons/mixer_monitor_input.png | Bin 1045 -> 1044 bytes gtk2_ardour/icons/mixer_mute.png | Bin 1153 -> 276 bytes gtk2_ardour/icons/mixer_mute_implicit.png | Bin 1170 -> 1155 bytes gtk2_ardour/icons/mixer_record.png | Bin 1148 -> 1119 bytes gtk2_ardour/icons/mixer_solo.png | Bin 1221 -> 1159 bytes gtk2_ardour/icons/mixer_solo_safe.png | Bin 1351 -> 1299 bytes gtk2_ardour/icons/mixer_strip_meter_marks.png | Bin 208 -> 201 bytes gtk2_ardour/mixer_bridge_view.cc | 411 ++++++++++++++++++ gtk2_ardour/mixer_bridge_view.h | 83 ++++ gtk2_ardour/mono_panner.cc | 12 +- gtk2_ardour/mono_panner.h | 2 +- gtk2_ardour/panner_interface.h | 4 +- gtk2_ardour/stereo_panner.cc | 12 +- gtk2_ardour/stereo_panner.h | 2 +- gtk2_ardour/ui/editor_window.xml | 39 +- gtk2_ardour/ui/mixer_bridge_view.xml | 12 + gtk2_ardour/ui/mixer_gain_meter.xml | 41 +- gtk2_ardour/ui/mixer_strip.xml | 273 ++++-------- gtk2_ardour/wscript | 1 + libs/gtkmm2ext/fader.cc | 13 +- libs/gtkmm2ext/gtkmm2ext/fader.h | 6 +- 24 files changed, 665 insertions(+), 255 deletions(-) create mode 100644 gtk2_ardour/mixer_bridge_view.cc create mode 100644 gtk2_ardour/mixer_bridge_view.h create mode 100644 gtk2_ardour/ui/mixer_bridge_view.xml diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 37da07335b..3cde505335 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -251,7 +251,6 @@ Editor::Editor () , editor_summary_pane (get_v_paned ("editor_summary_pane")) , inspector_home (get_container ("inspector_home")) , _master_bus_ui_home (get_container ("master_bus_ui_home")) - , _compact_meter_bridge_home (get_container ("compact_meter_bridge_home")) , vpacker (get_v_box ("vpacker")) , _tool_marker_button (get_waves_button ("tool_marker_button")) , _tool_zoom_button (get_waves_button ("tool_zoom_button")) @@ -315,7 +314,8 @@ Editor::Editor () /* we are a singleton */ PublicEditor::_instance = this; - _compact_meter_bridge_home.add (_compact_meter_bridge); + get_container ("compact_meter_bridge_home").add (_compact_meter_bridge); + get_container ("mixer_bridge_view_home").add (_mixer_bridge_view); _have_idled = false; @@ -1281,6 +1281,7 @@ Editor::set_session (Session *t) _routes->set_session (_session); _locations->set_session (_session); _compact_meter_bridge.set_session (_session); + _mixer_bridge_view.set_session (_session); if (rhythm_ferret) { rhythm_ferret->set_session (_session); diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 4494a34114..0b7cf3d9f2 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -58,6 +58,7 @@ #include "editor_items.h" #include "region_selection.h" #include "compact_meter_bridge.h" +#include "mixer_bridge_view.h" namespace Gtkmm2ext { class TearOff; @@ -688,7 +689,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD Gtk::Container& inspector_home; Gtk::Container& _master_bus_ui_home; - Gtk::Container& _compact_meter_bridge_home; MasterBusUI* _master_bus_ui; Gtk::VBox& vpacker; @@ -1901,6 +1901,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD MixerStrip *current_mixer_strip; CompactMeterbridge _compact_meter_bridge; + MixerBridgeView _mixer_bridge_view; bool show_editor_mixer_when_tracks_arrive; void cms_new (boost::shared_ptr); void current_mixer_strip_hidden (); diff --git a/gtk2_ardour/editor_mixer.cc b/gtk2_ardour/editor_mixer.cc index d584783c98..b9fc1d5407 100644 --- a/gtk2_ardour/editor_mixer.cc +++ b/gtk2_ardour/editor_mixer.cc @@ -255,6 +255,7 @@ void Editor::track_mixer_selection () { Mixer_UI::instance()->selection().RoutesChanged.connect (sigc::mem_fun (*this, &Editor::follow_mixer_selection)); + _mixer_bridge_view.track_editor_selection (); } void diff --git a/gtk2_ardour/icons/mixer_monitor_input.png b/gtk2_ardour/icons/mixer_monitor_input.png index 18624ee4decfbdf728e40ca9b4e4e1b6db36867f..dd9c954ceb017a505e529357fb9c8ead938a1f2a 100644 GIT binary patch delta 224 zcmbQrF@ZfJ8am-ow2diQ-p$3u#K_dm(89>T%)-#n(#Xlc(bdAh)yc%z+|12% zvITQpoYi0dRG{rno-U3d6}OVUeEj(Hyo37zrlpcEQx%1o=N??q+I;xXo;`a!6xJ+k#550t}8Q7%*ZLb`{JSMD~AqdD>^hVGQ>-6jY^zrR?Qr&VaSW-rmGtG~$HWC@35<`- z^X~;*4^U&1Y6x`hWLmdw-N%m~L(D?Fyu2bKD@_);@v5$JP-N4I*->EP(>`}010x&5 Xmq?DNSS2l0pm7YIu6{1-oD!M<(vduY diff --git a/gtk2_ardour/icons/mixer_mute.png b/gtk2_ardour/icons/mixer_mute.png index 6624a0204a1fcf328a61c0c1f7818a821c6d13a9..b2fa83560fe51b59a166a6c6a7fd2774a7d4324f 100644 GIT binary patch delta 259 zcmZqVoWe9gvYw5Bfni=;>`x%YUgGKN%6^YshEORjsQR+HtlfIj)d6t8<6>>qKsm{pk)Y`hg8MELs}B2golqba+%`%G}#L zrIAsv#fwLUO?{`>yT)I9mRp5*B^GWyn(@#!>*0f~0t}j;vg_HCfOsxk!*rUs}wgKnT!ll+WcmF+{Z$b%UO9Z2%C zPIc$IfJS@_q5_PVFor-(7LW`TS@{k~5J3@1B8*26RHJbfA~5&x%$jfYsRcbdXN#SZ ze3?>D6~#)WB2?N0;`fV4Q4|qMq9jEaA`*U_(uVjsw%TJ!%sdgc^-rGDMR+ z^K>=@$IIvE6}!P)qFBnrs^N)9fTH7sam}CuTEJi2SP&hQMm#JQa6pE9lhvbdLygRG z_jN-dka?qi@7t^>#-L8jAqTrOrzd%KBUrYjCX`exk=5gpF2Ps=p@fEHO^!=QOTe@O zQBB7}Tq&)j+F)AF%CQVWnYNUi(lVNibUl`d#uMopH|GY_a7|pZYcsoZ+_tZBRn5l+ zC4PyJ!CD7&l?f$5nRq}eMg;`&hH1N@BrMQuygK&nVQgi6;((b9tM&pOBvSts`7GD^ zKUou*Gh)~t|7w?-i1lE&oo{}2m>(bPvYGMOa4f3-bD9m-^_-q6RiD2(+qXgcy@ z{L=JJ>omC8(fn!E!+l(C)3Jm1{uj}8ly!^)==uevY^;64e zF!lP;y7AILqc_>|;G609d$%mU@$~Z9U(w!Y=g^WXw}*?Z`o7=M*aW${e{ySm)3-lQ zHPy8qzE}sEd)Aox@SBy~%kk`;i5o>pkBi62iVL^HpF%Fvsb5R?9Qq6keRu2t diff --git a/gtk2_ardour/icons/mixer_mute_implicit.png b/gtk2_ardour/icons/mixer_mute_implicit.png index 177bc647199b04ad32bdd2b2c96b81504817e40b..3690d93b18b75af97f0d21d9c641e808e5f82d6a 100644 GIT binary patch delta 336 zcmbQl*~~dXl7o$bfni=;?9YvgmP`uHE{=w#Mn;xyE*3_HhOWj=My_toMlKeH#;&Fo zPOb)%tC(b9iY#y{+QyVD@8;rSVr1%OXklbvW?^V(Y2;+!=xSl$>SSVUZsuk>*@C&Q zetYqw4?x>Ddb&7V4-;1|ps@6T}>U$z^dePilRiDcQby zp&e&ylH&@AvpRQ}zfR;9+3(I3w@OXwi300SKMh`~>8mqkm+*Kvu5igJn3VlcZpHg| z6Q$-XVRnY2i&_*crkRyfFOyzfBvM?sB*| zuuX{dW_50qW8cO1B3psUNa3MFoy)RKbLh*2~7ZTT%)-#n(#Xlc(bdAh)yc%z+|12%vITQp z{U6u+&w;l0db&7i(_2eJi`gE9E9um zk8EzJIKRYm@``uPjtXUso4z|3cI@ZUa*vf)Vw~VQ*P~{_`rd_)Og08^o?O20LV~Tg zxBN0kL!J-^-KCLQYa6Ed^jt`Ivmkw2!_nE?d$n|G`lmE?GWA@zm9*u9+}45*Q5*sZ Z4Bc|#FS`WU%7HFp@O1TaS?83{1OV*+YB~S_ delta 303 zcmcc5@rPrABnJ}%1B0N=sdXC_EtwRYoSYm@%v>GaOw3#i4PA{LO&pzFolOi~T+Cce z%`KcJS24-J6j|a_w2dj5(Q&c@lfq;x=9+rb8%vadcC7MraSW-rmGtG~$HWC@35<`- z^X~;*4^U&1Y7orR;I7Nm)YJ?Q54ZS!ykCB~|NMRB@8w+eo<4XG5EjN}^scFK(xjk@ z3JZ00byvMsh6RQ0eKL(3?%uhhqN@7QdYXoFYfDQ*9*a>)Ny)zY|Ns8{EY{j_g@s4q zO|1LwGRCt@n-)4WE8Oev?`N-)mlL_-8Fb(P>!b+_7R*|BK!sI>^O&9ThAC3I0dA`n cGBC0+1pKq%nVu^r0(3Tmr>mdKI;Vst05}zFTL1t6 diff --git a/gtk2_ardour/icons/mixer_solo.png b/gtk2_ardour/icons/mixer_solo.png index ac258874ecc51b47fa646f03d0b56c9b74b87815..f599b4919ac538408c4813914cec3fc8a1925c13 100644 GIT binary patch delta 340 zcmX@g+0HpZl7o$bfni=;?9YvgmP`uH7Ou`N&W=WIE+%eSSVUZsuk>*@C&Q zp6}BweW2}IJzX3_DsClx`S|hYc?b6cOiLwSrYZ_E&po)J)x_I`#W5~Uu0x3B(M$&! zE>Sz~BXb@0R9#x)Y4Y)*mO>fhBLfYwmM+b}yX^rCo8HI?yk~s$Js`*Dv_%Z>*R$3N zcFd&*vQ{W(Bq?f0TwXY>p(c!PYec7*n3kh%&<^&k5+PQh4v!6|gxS4mNGg%vyWDlr zPIg|u39aQ5k2u~;5?dSeQb(iA@l^YJPs0YmDBIp^VvEIuco~>@7}R-{8-LCHUJdjC NgQu&X%Q~loCIGK*bFlyb delta 377 zcmZqYJjyvil7oqXfkDvb)Vhs|mP`sJmQIcqE-o%^CT6aNhOWkrCXUXo&L)N~E@rN# z<`zzqtC(b9ikxvO+QyX3=r~z{Nnx@Tb4~r5$hTX7c6|19aSW-rmGtG~$HWC@35<`- z^X~;*4^U&1Y7orR;C2+9GiOd+UEQr)w;aB0PCw5lZ&&m6Rj602l$hAEB}=vl@mN?` z96EfMm6cVqbmgW^pLUnOe|LBHcUhh#OO|kCC58nD|Niz?T23@6De2RvPusR_d-dv- z!@Hy1_2T#U*ZZ$rctGIKpP!%S+t)YvvCYa$NMI28`SCIP&o-v!^GA+6xw<;sy-()m z{`&v#@9#G?F=;5Xsru5fsH2FP`N@fc?|l>!Sj04be73u=bltjj2U=JkGEKe$v|h9K zuWv$}=^1W^Hkh^l)Zm;$iTckt67)G^2DPFaQ`lUHx3vIVCg! E0MeVD2LJ#7 diff --git a/gtk2_ardour/icons/mixer_solo_safe.png b/gtk2_ardour/icons/mixer_solo_safe.png index 4192219dafe065c2ca2b65ad1d19f31ec0e64182..c4407b889cee031ce2dcc7dcd78ba33279c6d560 100644 GIT binary patch delta 481 zcmX@kHJNLIBnKM<1H-(y*q<8}EtwRYT^tQfjf`B}Tr7+X4PA|$j9lHEja)1Yja^MG zoLmhiS24-J6glHmw2diQ-p$3u#K_dm(89>T%)-#n(#Xlc(bdAh)yc%z+|12%vITQp zz1H(n^B5Qy9X(wfLn>}1?YXD$b$(-C1FK8M75mgBQ(32XOWte<;TCXb+-M@KTg$w~ zN7h4@IZ0IE8gr-N#S5EK6iOvJ(qDf2$ItYr{DZ>MO|E|&viPoqZ*%C*Q#yV5PFJ+?%`VHJP4b1k!1Vfq5T2;Nc_UmX_KWUDJe6V9JnD5ib! zkdx{P*6$0%nu7vaP2`+2pC0DZaQl9-dQ}9+8Ll*kGdxf4HM6Oo*tFZ>k9?M;M)a9Q z8dDdE?%<1esA1PKDS(v@d$ax%NOV`y;6Z zteZ0e-Z<*0gggimHV_O3kxjEC_S@SojuvKCIKZ%SZ=4D1w6p!d$Yk(z^>bP0l+XkK D7gn!E delta 508 zcmbQtb)0L0BnJ}%1B0N=sdXC_EtwQdES(%JTwD#^Ow3#j4PA{LO&pzFolOi~T+Cce z%`KcJS24-J6dB-Dw2dj5(Q&c@lfq;x=9>C*QSHAO7#K@ET^vIyZYAxxr*PCE_W;w8 zPU|Nt5(FOC*Y7<3Y*9YTjXJ}?qnSc;?w>AQ-%ACOlQ@3*u_UZyyI<-ecjJLCd?Fp8g^AMy0} zu|xTdZ|d9Qca+;qwfY?FF(L<5H{|LWUZS2ZYPQaCIiukqo*mzHo;C0000< KMNUMnLSTYraY0)E diff --git a/gtk2_ardour/mixer_bridge_view.cc b/gtk2_ardour/mixer_bridge_view.cc new file mode 100644 index 0000000000..b5e3b5d2bd --- /dev/null +++ b/gtk2_ardour/mixer_bridge_view.cc @@ -0,0 +1,411 @@ +/* + Copyright (C) 2014 Waves Audio Ltd. + + 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 +#include + +#include + +#include + +#include +#include +#include + +#include "ardour/debug.h" +#include "ardour/midi_track.h" +#include "ardour/route_group.h" +#include "ardour/session.h" + +#include "ardour/audio_track.h" +#include "ardour/midi_track.h" + +#include "mixer_bridge_view.h" + +#include "keyboard.h" +#include "monitor_section.h" +#include "public_editor.h" +#include "ardour_ui.h" +#include "utils.h" +#include "route_sorter.h" +#include "actions.h" +#include "gui_thread.h" +#include "global_signals.h" +#include "meter_patterns.h" + +#include "i18n.h" + +using namespace ARDOUR; +using namespace PBD; +using namespace Gtk; +using namespace Glib; +using namespace Gtkmm2ext; +using namespace std; +using namespace ArdourMeter; + +using PBD::atoi; + +struct SignalOrderRouteSorter { + bool operator() (boost::shared_ptr a, boost::shared_ptr b) { + if (a->is_master() || a->is_monitor()) { + /* "a" is a special route (master, monitor, etc), and comes + * last in the mixer ordering + */ + return false; + } else if (b->is_master() || b->is_monitor()) { + /* everything comes before b */ + return true; + } + return a->order_key () < b->order_key (); + } +}; + +MixerBridgeView::MixerBridgeView () + : Gtk::EventBox() + , WavesUI ("mixer_bridge_view.xml", *this) + , _mixer_strips_home (get_box ("mixer_strips_home")) + , _following_editor_selection (false) +{ + set_attributes (*this, *xml_tree ()->root (), XMLNodeMap ()); + signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler)); + Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&MixerBridgeView::sync_order_keys, this), gui_context()); + MixerStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&MixerBridgeView::remove_strip, this, _1), gui_context()); +} + +MixerBridgeView::~MixerBridgeView () +{ +} + +void +MixerBridgeView::set_session (Session* s) +{ + SessionHandlePtr::set_session (s); + + if (!_session) { + return; + } + + boost::shared_ptr routes = _session->get_routes(); + + add_strips(*routes); + + _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&MixerBridgeView::add_strips, this, _1), gui_context()); + + start_updating (); +} + +void +MixerBridgeView::track_editor_selection () +{ + PublicEditor::instance().get_selection().TracksChanged.connect (sigc::mem_fun (*this, &MixerBridgeView::follow_editor_selection)); +} + +void +MixerBridgeView::session_going_away () +{ + ENSURE_GUI_THREAD (*this, &MixerBridgeView::session_going_away); + + for (std::map , MixerStrip*>::iterator i = _strips.begin(); i != _strips.end(); ++i) { + delete (*i).second; + } + + _strips.clear (); + stop_updating (); + + SessionHandlePtr::session_going_away (); + _session = 0; +} + +gint +MixerBridgeView::start_updating () +{ + fast_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &MixerBridgeView::fast_update_strips)); + return 0; +} + +gint +MixerBridgeView::stop_updating () +{ + fast_screen_update_connection.disconnect(); + return 0; +} + +void +MixerBridgeView::fast_update_strips () +{ + if (!is_mapped () || !_session) { + return; + } + for (std::map , MixerStrip*>::iterator i = _strips.begin(); i != _strips.end(); ++i) { + (*i).second->fast_update (); + } +} + +void +MixerBridgeView::add_strips (RouteList& routes) +{ + // First detach all the prviously added strips from the ui tree. + for (std::map, MixerStrip*>::iterator i = _strips.begin(); i != _strips.end(); ++i) { + _mixer_strips_home.remove (*(*i).second); // we suppose _mixer_strips_home is + // the parnet. + } + + // Now create the strips for newly added routes + for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { + boost::shared_ptr route = (*x); + if (route->is_auditioner() || route->is_monitor() || route->is_master()) { + continue; + } + + MixerStrip* strip = strip = new MixerStrip (*ARDOUR_UI::instance()->the_mixer(), _session, route, "mixer_strip.xml"); + strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &MixerBridgeView::strip_button_release_event), strip)); + _strips [route] = strip; + strip->show(); + } + + // Now sort the session's routes and pack the strips accordingly + SignalOrderRouteSorter sorter; + RouteList copy(*_session->get_routes()); + copy.sort(sorter); + + for (RouteList::iterator x = copy.begin(); x != copy.end(); ++x) { + boost::shared_ptr route = (*x); + if (route->is_auditioner() || route->is_monitor() || route->is_master()) { + continue; + } + std::map , MixerStrip*>::iterator i = _strips.find (route); + if (i != _strips.end ()) { + _mixer_strips_home.pack_start (*(*i).second, false, false); + } + } +} + +void +MixerBridgeView::remove_strip (MixerStrip* strip) +{ + if (_session && _session->deletion_in_progress()) { + return; + } + + boost::shared_ptr route = strip->route (); + std::map , MixerStrip*>::iterator i = _strips.find (route); + if (i != _strips.end ()) { + _strips.erase (i); + } +} + +void +MixerBridgeView::sync_order_keys () +{ + Glib::Threads::Mutex::Lock lm (_resync_mutex); + + if (!_session) { + return; + } + + SignalOrderRouteSorter sorter; + boost::shared_ptr routes = _session->get_routes(); + + for (std::map, MixerStrip*>::iterator i = _strips.begin(); i != _strips.end(); ++i) { + _mixer_strips_home.remove (*(*i).second); // we suppose _mixer_strips_home is + // the parnet. + } + + RouteList copy(*routes); + copy.sort(sorter); + + for (RouteList::iterator x = copy.begin(); x != copy.end(); ++x) { + boost::shared_ptr route = (*x); + if (route->is_auditioner() || route->is_monitor() || route->is_master()) { + continue; + } + std::map , MixerStrip*>::iterator i = _strips.find (route); + if (i != _strips.end ()) { + _mixer_strips_home.pack_start (*(*i).second, false, false); + } + } +} + +void +MixerBridgeView::follow_editor_selection () +{ + if (_following_editor_selection) { + return; + } + + _following_editor_selection = true; + _selection.block_routes_changed (true); + + TrackSelection& s (PublicEditor::instance().get_selection().tracks); + + _selection.clear_routes (); + + for (TrackViewList::iterator i = s.begin(); i != s.end(); ++i) { + RouteTimeAxisView* rtav = dynamic_cast (*i); + if (rtav) { + MixerStrip* ms = strip_by_route (rtav->route()); + if (ms) { + _selection.add (ms); + } + } + } + + _following_editor_selection = false; + _selection.block_routes_changed (false); +} + +void +MixerBridgeView::set_route_targets_for_operation () +{ + _route_targets.clear (); + + if (!_selection.empty()) { + _route_targets = _selection.routes; + return; + } + + /* nothing selected ... 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); + } +} + +void +MixerBridgeView::toggle_midi_input_active (bool flip_others) +{ + boost::shared_ptr rl (new RouteList); + bool onoff = false; + + set_route_targets_for_operation (); + + for (RouteUISelection::iterator r = _route_targets.begin(); r != _route_targets.end(); ++r) { + boost::shared_ptr mt = (*r)->midi_track(); + + if (mt) { + rl->push_back ((*r)->route()); + onoff = !mt->input_active(); + } + } + + _session->set_exclusive_input_active (rl, onoff, flip_others); +} + +bool +MixerBridgeView::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip) +{ + if (ev->button == 1) { + 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::PrimaryModifier)) { + _selection.add (strip); + } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::RangeSelectModifier)) { + + if (!_selection.selected(strip)) { + + /* extend selection */ + + vector tmp; + bool accumulate = false; + + tmp.push_back (strip); + + for (std::map, MixerStrip*>::iterator i = _strips.begin(); i != _strips.end(); ++i) { + if ((*i).second == 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).second)) { + /* 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).second); + } + } + } + + for (vector::iterator i = tmp.begin(); i != tmp.end(); ++i) { + _selection.add (*i); + } + } + + } else { + _selection.set (strip); + } + } + } + + return true; +} + + +MixerStrip* +MixerBridgeView::strip_by_route (boost::shared_ptr route) +{ + std::map , MixerStrip*>::iterator i = _strips.find (route); + if (i != _strips.end ()) { + return (*i).second; + } + + return 0; +} + +MixerStrip* +MixerBridgeView::strip_by_x (int x) +{ + for (std::map, MixerStrip*>::iterator i = _strips.begin(); i != _strips.end(); ++i) { + int x1, x2, y; + + (*i).second->translate_coordinates (*this, 0, 0, x1, y); + x2 = x1 + (*i).second->get_width(); + + if (x >= x1 && x <= x2) { + return (*i).second; + } + } + + return 0; +} diff --git a/gtk2_ardour/mixer_bridge_view.h b/gtk2_ardour/mixer_bridge_view.h new file mode 100644 index 0000000000..997283b49e --- /dev/null +++ b/gtk2_ardour/mixer_bridge_view.h @@ -0,0 +1,83 @@ +/* + Copyright (C) 2014 Waves Audio Ltd. + + 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 __ardour_mixer_bridge_view_h__ +#define __ardour_mixer_bridge_view_h__ + +#include + +#include +#include +#include +#include + +#include "ardour/ardour.h" +#include "ardour/types.h" +#include "ardour/session_handle.h" + +#include "pbd/stateful.h" +#include "pbd/signals.h" + +#include "gtkmm2ext/visibility_tracker.h" + +#include "waves_ui.h" +#include "mixer_strip.h" +#include "mixer_actor.h" + +class MixerBridgeView : + public Gtk::EventBox, + public WavesUI, + public PBD::ScopedConnectionList, + public ARDOUR::SessionHandlePtr, + public MixerActor +{ + public: + MixerBridgeView (); + ~MixerBridgeView(); + void set_session (ARDOUR::Session *); + void track_editor_selection (); + + protected: + void set_route_targets_for_operation (); + void toggle_midi_input_active (bool flip_others); + + private: + Gtk::Box& _mixer_strips_home; + bool _following_editor_selection; + + gint start_updating (); + gint stop_updating (); + + sigc::connection fast_screen_update_connection; + void fast_update_strips (); + + void add_strips (ARDOUR::RouteList&); + void remove_strip (MixerStrip *); + + void session_going_away (); + void sync_order_keys (); + void follow_editor_selection (); + bool strip_button_release_event (GdkEventButton*, MixerStrip*); + MixerStrip* strip_by_route (boost::shared_ptr route); + MixerStrip* strip_by_x (int x); + + std::map , MixerStrip*> _strips; + mutable Glib::Threads::Mutex _resync_mutex; +}; + +#endif //__ardour_mixer_bridge_view_h__ diff --git a/gtk2_ardour/mono_panner.cc b/gtk2_ardour/mono_panner.cc index 7ce9a9d88b..059892e1b0 100644 --- a/gtk2_ardour/mono_panner.cc +++ b/gtk2_ardour/mono_panner.cc @@ -105,20 +105,18 @@ MonoPanner::set_tooltip () _tooltip.set_tip (buf); } -bool -MonoPanner::on_expose_event (GdkEventExpose*) +void +MonoPanner::render (cairo_t* cr) { - Cairo::RefPtr context = get_window()->create_cairo_context(); unsigned pos = (unsigned)(rint (100.0 * position_control->get_value ())); /* 0..100 */ double x = (get_width() - _knob_image[pos]->get_width())/2.0; double y = (get_height() - _knob_image[pos]->get_height())/2.0; - cairo_rectangle (context->cobj(), x, y, _knob_image[pos]->get_width(), _knob_image[pos]->get_height()); + cairo_rectangle (cr, x, y, _knob_image[pos]->get_width(), _knob_image[pos]->get_height()); - gdk_cairo_set_source_pixbuf (context->cobj(), _knob_image[pos]->gobj(), x, y); - cairo_fill (context->cobj()); - return true; + gdk_cairo_set_source_pixbuf (cr, _knob_image[pos]->gobj(), x, y); + cairo_fill (cr); } bool diff --git a/gtk2_ardour/mono_panner.h b/gtk2_ardour/mono_panner.h index e8bcb6a08e..8b2d2a4b50 100644 --- a/gtk2_ardour/mono_panner.h +++ b/gtk2_ardour/mono_panner.h @@ -48,7 +48,7 @@ class MonoPanner : public PannerInterface sigc::signal StopGesture; protected: - bool on_expose_event (GdkEventExpose*); + void render (cairo_t* cr); bool on_button_press_event (GdkEventButton*); bool on_button_release_event (GdkEventButton*); bool on_motion_notify_event (GdkEventMotion*); diff --git a/gtk2_ardour/panner_interface.h b/gtk2_ardour/panner_interface.h index 1aef6e4654..8e91737789 100644 --- a/gtk2_ardour/panner_interface.h +++ b/gtk2_ardour/panner_interface.h @@ -21,10 +21,10 @@ #define __gtk_ardour_panner_interface_h__ #include -#include #include #include "gtkmm2ext/persistent_tooltip.h" #include "pbd/destructible.h" +#include "gtkmm2ext/cairo_widget.h" namespace ARDOUR { class Panner; @@ -48,7 +48,7 @@ private: /** Parent class for some panner UI classes that contains some common code */ -class PannerInterface : public Gtk::DrawingArea, public PBD::Destructible +class PannerInterface : public CairoWidget, public PBD::Destructible { public: PannerInterface (boost::shared_ptr); diff --git a/gtk2_ardour/stereo_panner.cc b/gtk2_ardour/stereo_panner.cc index 4191e81708..a3d74a58ab 100644 --- a/gtk2_ardour/stereo_panner.cc +++ b/gtk2_ardour/stereo_panner.cc @@ -112,20 +112,18 @@ StereoPanner::set_tooltip () _tooltip.set_tip (buf); } -bool -StereoPanner::on_expose_event (GdkEventExpose*) +void +StereoPanner::render (cairo_t* cr) { - Cairo::RefPtr context = get_window()->create_cairo_context(); unsigned pos = (unsigned)(rint (100.0 * position_control->get_value ())); /* 0..100 */ double x = (get_width() - _knob_image[pos]->get_width())/2.0; double y = (get_height() - _knob_image[pos]->get_height())/2.0; - cairo_rectangle (context->cobj(), x, y, _knob_image[pos]->get_width(), _knob_image[pos]->get_height()); + cairo_rectangle (cr, x, y, _knob_image[pos]->get_width(), _knob_image[pos]->get_height()); - gdk_cairo_set_source_pixbuf (context->cobj(), _knob_image[pos]->gobj(), x, y); - cairo_fill (context->cobj()); - return true; + gdk_cairo_set_source_pixbuf (cr, _knob_image[pos]->gobj(), x, y); + cairo_fill (cr); } bool diff --git a/gtk2_ardour/stereo_panner.h b/gtk2_ardour/stereo_panner.h index 6e1b79bf96..6fa7f16097 100644 --- a/gtk2_ardour/stereo_panner.h +++ b/gtk2_ardour/stereo_panner.h @@ -51,7 +51,7 @@ class StereoPanner : public PannerInterface sigc::signal StopWidthGesture; protected: - bool on_expose_event (GdkEventExpose*); + void render (cairo_t* cr); bool on_button_press_event (GdkEventButton*); bool on_button_release_event (GdkEventButton*); bool on_motion_notify_event (GdkEventMotion*); diff --git a/gtk2_ardour/ui/editor_window.xml b/gtk2_ardour/ui/editor_window.xml index 8ca876527a..240b13402d 100644 --- a/gtk2_ardour/ui/editor_window.xml +++ b/gtk2_ardour/ui/editor_window.xml @@ -203,21 +203,30 @@ - - - + + + + + + + + + + - - - + + + table.yexpand="true" + bgnormal="#3E3E3E"> @@ -274,7 +284,10 @@ - + diff --git a/gtk2_ardour/ui/mixer_bridge_view.xml b/gtk2_ardour/ui/mixer_bridge_view.xml new file mode 100644 index 0000000000..9ea3b23e3a --- /dev/null +++ b/gtk2_ardour/ui/mixer_bridge_view.xml @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/gtk2_ardour/ui/mixer_gain_meter.xml b/gtk2_ardour/ui/mixer_gain_meter.xml index 1aef03a6d3..ca0c4308c5 100644 --- a/gtk2_ardour/ui/mixer_gain_meter.xml +++ b/gtk2_ardour/ui/mixer_gain_meter.xml @@ -3,7 +3,7 @@ - +