2 Copyright (C) 2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <gtkmm/stock.h>
21 #include "ardour/session.h"
22 #include "ardour/route_group.h"
23 #include "ardour/route.h"
25 #include "gui_thread.h"
26 #include "route_group_dialog.h"
27 #include "group_tabs.h"
33 using namespace ARDOUR
;
34 using Gtkmm2ext::Keyboard
;
36 GroupTabs::GroupTabs ()
39 , _dragging_new_tab (0)
44 GroupTabs::~GroupTabs ()
50 GroupTabs::set_session (Session
* s
)
52 SessionHandlePtr::set_session (s
);
55 _session
->RouteGroupChanged
.connect (_session_connections
, invalidator (*this), boost::bind (&GroupTabs::set_dirty
, this), gui_context());
60 /** Handle a size request.
61 * @param req GTK requisition
64 GroupTabs::on_size_request (Gtk::Requisition
*req
)
66 /* Use a dummy, small width and the actual height that we want */
72 GroupTabs::on_button_press_event (GdkEventButton
* ev
)
74 using namespace Menu_Helpers
;
76 double const p
= primary_coordinate (ev
->x
, ev
->y
);
78 list
<Tab
>::iterator prev
;
79 list
<Tab
>::iterator next
;
80 Tab
* t
= click_to_tab (p
, &prev
, &next
);
82 _drag_min
= prev
!= _tabs
.end() ? prev
->to
: 0;
83 _drag_max
= next
!= _tabs
.end() ? next
->from
: extent ();
85 if (ev
->button
== 1) {
90 _dragging_new_tab
= true;
92 if (next
== _tabs
.end()) {
96 list
<Tab
>::iterator j
= _tabs
.insert (next
, n
);
101 _dragging_new_tab
= false;
108 double const h
= (t
->from
+ t
->to
) / 2;
110 _drag_moving
= t
->from
;
112 _drag_offset
= p
- t
->from
;
114 _drag_moving
= t
->to
;
115 _drag_fixed
= t
->from
;
116 _drag_offset
= p
- t
->to
;
119 } else if (ev
->button
== 3) {
121 RouteGroup
* g
= t
? t
->group
: 0;
122 Menu
* m
= get_menu (g
);
124 m
->popup (ev
->button
, ev
->time
);
134 GroupTabs::on_motion_notify_event (GdkEventMotion
* ev
)
136 if (_dragging
== 0) {
140 double const p
= primary_coordinate (ev
->x
, ev
->y
);
142 if (p
!= _drag_first
) {
146 _drag_moving
= p
- _drag_offset
;
148 _dragging
->from
= min (_drag_moving
, _drag_fixed
);
149 _dragging
->to
= max (_drag_moving
, _drag_fixed
);
151 _dragging
->from
= max (_dragging
->from
, _drag_min
);
152 _dragging
->to
= min (_dragging
->to
, _drag_max
);
162 GroupTabs::on_button_release_event (GdkEventButton
* ev
)
164 if (_dragging
== 0) {
170 if (_dragging
->group
) {
172 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
175 RouteGroupDialog
d (_dragging
->group
, Gtk::Stock::APPLY
);
180 /* toggle active state */
181 _dragging
->group
->set_active (!_dragging
->group
->is_active (), this);
188 RouteList routes
= routes_for_tab (_dragging
);
190 if (!routes
.empty()) {
191 if (_dragging_new_tab
) {
192 RouteGroup
* g
= create_and_add_group ();
194 for (RouteList::iterator i
= routes
.begin(); i
!= routes
.end(); ++i
) {
199 boost::shared_ptr
<RouteList
> r
= _session
->get_routes ();
200 for (RouteList::iterator i
= r
->begin(); i
!= r
->end(); ++i
) {
202 if (find (routes
.begin(), routes
.end(), *i
) == routes
.end()) {
203 /* this route is not on the list of those that should be in _dragging's group */
204 if ((*i
)->route_group() == _dragging
->group
) {
205 _dragging
->group
->remove (*i
);
208 _dragging
->group
->add (*i
);
224 GroupTabs::render (cairo_t
* cr
)
226 if (_dragging
== 0) {
227 _tabs
= compute_tabs ();
232 cairo_set_source_rgb (cr
, 0, 0, 0);
233 cairo_rectangle (cr
, 0, 0, _width
, _height
);
238 for (list
<Tab
>::const_iterator i
= _tabs
.begin(); i
!= _tabs
.end(); ++i
) {
244 /** Convert a click position to a tab.
245 * @param c Click position.
246 * @param prev Filled in with the previous tab to the click, or 0.
247 * @param next Filled in with the next tab after the click, or 0.
248 * @return Tab under the click, or 0.
252 GroupTabs::click_to_tab (double c
, list
<Tab
>::iterator
* prev
, list
<Tab
>::iterator
* next
)
254 *prev
= *next
= _tabs
.end ();
257 list
<Tab
>::iterator i
= _tabs
.begin ();
258 while (i
!= _tabs
.end()) {
270 if (i
->from
<= c
&& c
< i
->to
) {
277 if (i
!= _tabs
.end()) {
289 GroupTabs::get_menu (RouteGroup
* g
)
291 using namespace Menu_Helpers
;
295 Menu
* new_from
= new Menu
;
296 MenuList
& f
= new_from
->items ();
297 f
.push_back (MenuElem (_("Selection..."), sigc::mem_fun (*this, &GroupTabs::new_from_selection
)));
298 f
.push_back (MenuElem (_("Record Enabled..."), sigc::mem_fun (*this, &GroupTabs::new_from_rec_enabled
)));
299 f
.push_back (MenuElem (_("Soloed..."), sigc::mem_fun (*this, &GroupTabs::new_from_soloed
)));
302 _menu
->set_name ("ArdourContextMenu");
303 MenuList
& items
= _menu
->items();
305 items
.push_back (MenuElem (_("New..."), hide_return (sigc::mem_fun(*this, &GroupTabs::create_and_add_group
))));
306 items
.push_back (MenuElem (_("New From"), *new_from
));
309 items
.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &GroupTabs::edit_group
), g
)));
310 items
.push_back (MenuElem (_("Subgroup"), sigc::bind (sigc::mem_fun (*this, &GroupTabs::subgroup
), g
)));
311 items
.push_back (MenuElem (_("Collect"), sigc::bind (sigc::mem_fun (*this, &GroupTabs::collect
), g
)));
312 items
.push_back (MenuElem (_("Remove"), sigc::bind (sigc::mem_fun (*this, &GroupTabs::remove_group
), g
)));
315 add_menu_items (_menu
, g
);
317 items
.push_back (SeparatorElem());
318 items
.push_back (MenuElem (_("Activate All"), sigc::mem_fun(*this, &GroupTabs::activate_all
)));
319 items
.push_back (MenuElem (_("Disable All"), sigc::mem_fun(*this, &GroupTabs::disable_all
)));
326 GroupTabs::new_from_selection ()
328 RouteList rl
= selected_routes ();
333 run_new_group_dialog (rl
);
337 GroupTabs::new_from_rec_enabled ()
339 boost::shared_ptr
<RouteList
> rl
= _session
->get_routes ();
341 RouteList rec_enabled
;
343 for (RouteList::iterator i
= rl
->begin(); i
!= rl
->end(); ++i
) {
344 if ((*i
)->record_enabled()) {
345 rec_enabled
.push_back (*i
);
349 if (rec_enabled
.empty()) {
353 run_new_group_dialog (rec_enabled
);
357 GroupTabs::new_from_soloed ()
359 boost::shared_ptr
<RouteList
> rl
= _session
->get_routes ();
363 for (RouteList::iterator i
= rl
->begin(); i
!= rl
->end(); ++i
) {
364 if (!(*i
)->is_master() && (*i
)->soloed()) {
365 soloed
.push_back (*i
);
369 if (soloed
.empty()) {
373 run_new_group_dialog (soloed
);
378 GroupTabs::run_new_group_dialog (RouteList
const & rl
)
380 RouteGroup
* g
= new RouteGroup (*_session
, "");
381 g
->set_properties (default_properties ());
383 RouteGroupDialog
d (g
, Gtk::Stock::NEW
);
384 int const r
= d
.do_run ();
387 case Gtk::RESPONSE_OK
:
388 case Gtk::RESPONSE_ACCEPT
:
389 _session
->add_route_group (g
);
390 for (RouteList::const_iterator i
= rl
.begin(); i
!= rl
.end(); ++i
) {
400 GroupTabs::create_and_add_group () const
402 RouteGroup
* g
= new RouteGroup (*_session
, "");
404 g
->set_properties (default_properties ());
406 RouteGroupDialog
d (g
, Gtk::Stock::NEW
);
407 int const r
= d
.do_run ();
409 if (r
!= Gtk::RESPONSE_OK
) {
414 _session
->add_route_group (g
);
419 GroupTabs::edit_group (RouteGroup
* g
)
421 RouteGroupDialog
d (g
, Gtk::Stock::APPLY
);
426 GroupTabs::subgroup (RouteGroup
* g
)
431 struct CollectSorter
{
432 CollectSorter (std::string
const & key
) : _key (key
) {}
434 bool operator () (boost::shared_ptr
<Route
> a
, boost::shared_ptr
<Route
> b
) {
435 return a
->order_key (_key
) < b
->order_key (_key
);
441 /** Collect all members of a RouteGroup so that they are together in the Editor or Mixer.
442 * @param g Group to collect.
445 GroupTabs::collect (RouteGroup
* g
)
447 boost::shared_ptr
<RouteList
> group_routes
= g
->route_list ();
448 group_routes
->sort (CollectSorter (order_key ()));
449 int const N
= group_routes
->size ();
451 RouteList::iterator i
= group_routes
->begin ();
452 boost::shared_ptr
<RouteList
> routes
= _session
->get_routes ();
453 RouteList::const_iterator j
= routes
->begin ();
457 while (i
!= group_routes
->end() && j
!= routes
->end()) {
459 int const k
= (*j
)->order_key (order_key ());
470 (*j
)->set_order_key (order_key (), coll
);
477 (*j
)->set_order_key (order_key (), k
+ diff
);
488 GroupTabs::activate_all ()
490 _session
->foreach_route_group (
491 sigc::bind (sigc::mem_fun (*this, &GroupTabs::set_activation
), true)
496 GroupTabs::disable_all ()
498 _session
->foreach_route_group (
499 sigc::bind (sigc::mem_fun (*this, &GroupTabs::set_activation
), false)
504 GroupTabs::set_activation (RouteGroup
* g
, bool a
)
506 g
->set_active (a
, this);
510 GroupTabs::remove_group (RouteGroup
* g
)
512 _session
->remove_route_group (*g
);